PALISADE Lattice Crypto Library  1.11.9
A lattice crypto library for software engineers by software engineers.
ringcore.h
1 // @file ringcore.h - Main ring classes for Boolean circuit FHE.
2 // @author TPOC: contact@palisade-crypto.org
3 //
4 // @copyright Copyright (c) 2019, Duality Technologies Inc.
5 // All rights reserved.
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
8 // 1. Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 // 2. Redistributions in binary form must reproduce the above copyright notice,
11 // this list of conditions and the following disclaimer in the documentation
12 // and/or other materials provided with the distribution. THIS SOFTWARE IS
13 // PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
14 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
15 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
16 // EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
17 // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 
24 #ifndef BINFHE_RINGCORE_H
25 #define BINFHE_RINGCORE_H
26 
27 #include <memory>
28 #include <string>
29 #include <utility>
30 #include <vector>
31 
32 #include "lattice/backend.h"
33 #include "lwecore.h"
34 #include "math/backend.h"
35 #include "math/discretegaussiangenerator.h"
36 #include "math/nbtheory.h"
37 #include "math/transfrm.h"
38 #include "utils/serializable.h"
39 
40 namespace lbcrypto {
41 
42 // enum for all supported binary gates
43 enum BINGATE { OR, AND, NOR, NAND, XOR_FAST, XNOR_FAST, XOR, XNOR };
44 
45 // Two variants of FHEW are supported based on the bootstrapping technique used:
46 // AP and GINX Please see "Bootstrapping in FHEW-like Cryptosystems" for details
47 // on both bootstrapping techniques
48 enum BINFHEMETHOD { AP, GINX };
49 
55  public:
57  : m_baseG(0), m_digitsG(0), m_digitsG2(0), m_baseR(0), m_method(GINX) {}
58 
67  explicit RingGSWCryptoParams(const std::shared_ptr<LWECryptoParams> lweparams,
68  uint32_t baseG, uint32_t baseR,
69  BINFHEMETHOD method)
70  : m_LWEParams(lweparams),
71  m_baseG(baseG),
72  m_baseR(baseR),
73  m_method(method) {
74  if (!IsPowerOfTwo(baseG)) {
75  PALISADE_THROW(config_error, "Gadget base should be a power of two.");
76  }
77 
78  PreCompute();
79  }
80 
84  void PreCompute() {
85  const shared_ptr<LWECryptoParams> lweparams = m_LWEParams;
86 
87  NativeInteger Q = lweparams->GetQ();
88  NativeInteger q = lweparams->Getq();
89  uint32_t N = lweparams->GetN();
90  NativeInteger rootOfUnity = RootOfUnity<NativeInteger>(2 * N, Q);
91 
92  // Precomputes the table with twiddle factors to support fast NTT
94  Q);
95 
96  // Precomputes a polynomial for MSB extraction
97  m_polyParams = std::make_shared<ILNativeParams>(2 * N, Q, rootOfUnity);
98 
99  m_digitsG = (uint32_t)std::ceil(log(Q.ConvertToDouble()) /
100  log(static_cast<double>(m_baseG)));
101  m_digitsG2 = m_digitsG * 2;
102 
103  // Computes baseR^i (only for AP bootstrapping)
104  if (m_method == AP) {
105  uint32_t digitCountR =
106  (uint32_t)std::ceil(log(static_cast<double>(q.ConvertToInt())) /
107  log(static_cast<double>(m_baseR)));
108  // Populate digits
109  NativeInteger value = 1;
110  for (uint32_t i = 0; i < digitCountR; i++) {
111  m_digitsR.push_back(value);
112  value *= m_baseR;
113  }
114  }
115 
116  // Computes baseG^i
117  NativeInteger vTemp = NativeInteger(1);
118  for (uint32_t i = 0; i < m_digitsG; i++) {
119  m_Gpower.push_back(vTemp);
120  vTemp = vTemp.ModMul(NativeInteger(m_baseG), Q);
121  }
122 
123  // Sets the gate constants for supported binary operations
124  m_gateConst = {
125  NativeInteger(5) * (q >> 3), // OR
126  NativeInteger(7) * (q >> 3), // AND
127  NativeInteger(1) * (q >> 3), // NOR
128  NativeInteger(3) * (q >> 3), // NAND
129  NativeInteger(5) * (q >> 3), // XOR_FAST
130  NativeInteger(1) * (q >> 3) // XNOR_FAST
131  };
132 
133  // Computes polynomials X^m - 1 that are needed in the accumulator for the
134  // GINX bootstrapping
135  if (m_method == GINX) {
136  // loop for positive values of m
137  for (uint32_t i = 0; i < N; i++) {
138  NativePoly aPoly = NativePoly(m_polyParams, Format::COEFFICIENT, true);
139  aPoly[i].ModAddEq(NativeInteger(1), Q); // X^m
140  aPoly[0].ModSubEq(NativeInteger(1), Q); // -1
141  aPoly.SetFormat(Format::EVALUATION);
142  m_monomials.push_back(aPoly);
143  }
144 
145  // loop for negative values of m
146  for (uint32_t i = 0; i < N; i++) {
147  NativePoly aPoly = NativePoly(m_polyParams, Format::COEFFICIENT, true);
148  aPoly[i].ModSubEq(NativeInteger(1), Q); // -X^m
149  aPoly[0].ModSubEq(NativeInteger(1), Q); // -1
150  aPoly.SetFormat(Format::EVALUATION);
151  m_monomials.push_back(aPoly);
152  }
153  }
154 #if defined(BINFHE_DEBUG)
155  std::cerr << "base_g = " << m_baseG << std::endl;
156  std::cerr << "m_digitsG = " << m_digitsG << std::endl;
157  std::cerr << "m_digitsG2 = " << m_digitsG2 << std::endl;
158  std::cerr << "m_baseR = " << m_baseR << std::endl;
159  std::cerr << "m_digitsR = " << m_digitsR << std::endl;
160  std::cerr << "m_Gpower = " << m_Gpower << std::endl;
161  std::cerr << "n = " << m_LWEParams->Getn() << std::endl;
162  std::cerr << "N = " << m_LWEParams->GetN() << std::endl;
163  std::cerr << "q = " << m_LWEParams->Getq() << std::endl;
164  std::cerr << "Q = " << m_LWEParams->GetQ() << std::endl;
165  std::cerr << "baseKS = " << m_LWEParams->GetBaseKS() << std::endl;
166  std::cerr << "digitsKS = " << m_LWEParams->GetDigitsKS() << std::endl;
167 #endif
168  }
169 
170  const std::shared_ptr<LWECryptoParams> GetLWEParams() const {
171  return m_LWEParams;
172  }
173 
174  uint32_t GetBaseG() const { return m_baseG; }
175 
176  uint32_t GetDigitsG() const { return m_digitsG; }
177 
178  uint32_t GetDigitsG2() const { return m_digitsG2; }
179 
180  uint32_t GetBaseR() const { return m_baseR; }
181 
182  const std::vector<NativeInteger>& GetDigitsR() const { return m_digitsR; }
183 
184  const shared_ptr<ILNativeParams> GetPolyParams() const {
185  return m_polyParams;
186  }
187 
188  const std::vector<NativeInteger>& GetGPower() const { return m_Gpower; }
189 
190  const std::vector<NativeInteger>& GetGateConst() const { return m_gateConst; }
191 
192  const NativePoly& GetMonomial(uint32_t i) const { return m_monomials[i]; }
193 
194  BINFHEMETHOD GetMethod() const { return m_method; }
195 
196  bool operator==(const RingGSWCryptoParams& other) const {
197  return *m_LWEParams == *other.m_LWEParams && m_baseR == other.m_baseR &&
198  m_baseG == other.m_baseG && m_method == other.m_method;
199  }
200 
201  bool operator!=(const RingGSWCryptoParams& other) const {
202  return !(*this == other);
203  }
204 
205  template <class Archive>
206  void save(Archive& ar, std::uint32_t const version) const {
207  ar(::cereal::make_nvp("params", m_LWEParams));
208  ar(::cereal::make_nvp("bR", m_baseR));
209  ar(::cereal::make_nvp("bG", m_baseG));
210  ar(::cereal::make_nvp("method", m_method));
211  }
212 
213  template <class Archive>
214  void load(Archive& ar, std::uint32_t const version) {
215  if (version > SerializedVersion()) {
216  PALISADE_THROW(deserialize_error,
217  "serialized object version " + std::to_string(version) +
218  " is from a later version of the library");
219  }
220  ar(::cereal::make_nvp("params", m_LWEParams));
221  ar(::cereal::make_nvp("bR", m_baseR));
222  ar(::cereal::make_nvp("bG", m_baseG));
223  ar(::cereal::make_nvp("method", m_method));
224 
225  this->PreCompute();
226  }
227 
228  std::string SerializedObjectName() const { return "RingGSWCryptoParams"; }
229  static uint32_t SerializedVersion() { return 1; }
230 
231  private:
232  // shared pointer to an instance of LWECryptoParams
233  std::shared_ptr<LWECryptoParams> m_LWEParams;
234 
235  // gadget base used in bootstrapping
236  uint32_t m_baseG;
237 
238  // number of digits in decomposing integers mod Q
239  uint32_t m_digitsG;
240 
241  // twice the number of digits in decomposing integers mod Q
242  uint32_t m_digitsG2;
243 
244  // base used for the refreshing key (used only for AP bootstrapping)
245  uint32_t m_baseR;
246 
247  // powers of m_baseR (used only for AP bootstrapping)
248  std::vector<NativeInteger> m_digitsR;
249 
250  // A vector of powers of baseG
251  std::vector<NativeInteger> m_Gpower;
252 
253  // Parameters for polynomials in RingGSW/RingLWE
254  shared_ptr<ILNativeParams> m_polyParams;
255 
256  // Constants used in evaluating binary gates
257  std::vector<NativeInteger> m_gateConst;
258 
259  // Precomputed polynomials in Format::EVALUATION representation for X^m - 1
260  // (used only for GINX bootstrapping)
261  std::vector<NativePoly> m_monomials;
262 
263  // Bootstrapping method (AP or GINX)
264  BINFHEMETHOD m_method;
265 };
266 
272  public:
273  RingGSWCiphertext() {}
274 
275  RingGSWCiphertext(uint32_t rowSize, uint32_t colSize) {
276  m_elements.resize(rowSize);
277  for (uint32_t i = 0; i < rowSize; i++) m_elements[i].resize(colSize);
278  }
279 
280  explicit RingGSWCiphertext(
281  const std::vector<std::vector<NativePoly>>& elements)
282  : m_elements(elements) {}
283 
284  explicit RingGSWCiphertext(const RingGSWCiphertext& rhs) {
285  this->m_elements = rhs.m_elements;
286  }
287 
288  explicit RingGSWCiphertext(const RingGSWCiphertext&& rhs) {
289  this->m_elements = std::move(rhs.m_elements);
290  }
291 
292  const RingGSWCiphertext& operator=(const RingGSWCiphertext& rhs) {
293  this->m_elements = rhs.m_elements;
294  return *this;
295  }
296 
297  const RingGSWCiphertext& operator=(const RingGSWCiphertext&& rhs) {
298  this->m_elements = rhs.m_elements;
299  return *this;
300  }
301 
302  const std::vector<std::vector<NativePoly>>& GetElements() const {
303  return m_elements;
304  }
305 
306  void SetElements(const std::vector<std::vector<NativePoly>>& elements) {
307  m_elements = elements;
308  }
309 
314  void SetFormat(const Format format) {
315  for (uint32_t i = 0; i < m_elements.size(); i++)
316  // column size is assume to be the same
317  for (uint32_t j = 0; j < m_elements[0].size(); j++)
318  m_elements[i][j].SetFormat(format);
319  }
320 
321  std::vector<NativePoly>& operator[](uint32_t i) { return m_elements[i]; }
322 
323  const std::vector<NativePoly>& operator[](usint i) const {
324  return m_elements[i];
325  }
326 
327  bool operator==(const RingGSWCiphertext& other) const {
328  return m_elements == other.m_elements;
329  }
330 
331  bool operator!=(const RingGSWCiphertext& other) const {
332  return !(*this == other);
333  }
334 
335  template <class Archive>
336  void save(Archive& ar, std::uint32_t const version) const {
337  ar(::cereal::make_nvp("elements", m_elements));
338  }
339 
340  template <class Archive>
341  void load(Archive& ar, std::uint32_t const version) {
342  if (version > SerializedVersion()) {
343  PALISADE_THROW(deserialize_error,
344  "serialized object version " + std::to_string(version) +
345  " is from a later version of the library");
346  }
347  ar(::cereal::make_nvp("elements", m_elements));
348  }
349 
350  std::string SerializedObjectName() const { return "RingGSWCiphertext"; }
351  static uint32_t SerializedVersion() { return 1; }
352 
353  private:
354  std::vector<std::vector<NativePoly>> m_elements;
355 };
356 
361 class RingGSWBTKey : public Serializable {
362  public:
363  RingGSWBTKey() {}
364 
365  explicit RingGSWBTKey(uint32_t dim1, uint32_t dim2, uint32_t dim3) {
366  m_key.resize(dim1);
367  for (uint32_t i = 0; i < dim1; i++) {
368  m_key[i].resize(dim2);
369  for (uint32_t j = 0; j < dim2; j++) m_key[i][j].resize(dim3);
370  }
371  }
372 
373  explicit RingGSWBTKey(
374  const std::vector<std::vector<std::vector<RingGSWCiphertext>>>& key)
375  : m_key(key) {}
376 
377  explicit RingGSWBTKey(const RingGSWBTKey& rhs) { this->m_key = rhs.m_key; }
378 
379  explicit RingGSWBTKey(const RingGSWBTKey&& rhs) {
380  this->m_key = std::move(rhs.m_key);
381  }
382 
383  const RingGSWBTKey& operator=(const RingGSWBTKey& rhs) {
384  this->m_key = rhs.m_key;
385  return *this;
386  }
387 
388  const RingGSWBTKey& operator=(const RingGSWBTKey&& rhs) {
389  this->m_key = std::move(rhs.m_key);
390  return *this;
391  }
392 
393  const std::vector<std::vector<std::vector<RingGSWCiphertext>>>& GetElements()
394  const {
395  return m_key;
396  }
397 
398  void SetElements(
399  const std::vector<std::vector<std::vector<RingGSWCiphertext>>>& key) {
400  m_key = key;
401  }
402 
403  std::vector<std::vector<RingGSWCiphertext>>& operator[](uint32_t i) {
404  return m_key[i];
405  }
406 
407  const std::vector<std::vector<RingGSWCiphertext>>& operator[](usint i) const {
408  return m_key[i];
409  }
410 
411  bool operator==(const RingGSWBTKey& other) const {
412  return m_key == other.m_key;
413  }
414 
415  bool operator!=(const RingGSWBTKey& other) const { return !(*this == other); }
416 
417  template <class Archive>
418  void save(Archive& ar, std::uint32_t const version) const {
419  ar(::cereal::make_nvp("key", m_key));
420  }
421 
422  template <class Archive>
423  void load(Archive& ar, std::uint32_t const version) {
424  if (version > SerializedVersion()) {
425  PALISADE_THROW(deserialize_error,
426  "serialized object version " + std::to_string(version) +
427  " is from a later version of the library");
428  }
429  ar(::cereal::make_nvp("key", m_key));
430  }
431 
432  std::string SerializedObjectName() const { return "RingGSWBTKey"; }
433  static uint32_t SerializedVersion() { return 1; }
434 
435  private:
436  std::vector<std::vector<std::vector<RingGSWCiphertext>>> m_key;
437 };
438 
439 // The struct for storing bootstrapping keys
440 typedef struct {
441  // refreshing key
442  std::shared_ptr<RingGSWBTKey> BSkey;
443  // switching key
444  std::shared_ptr<LWESwitchingKey> KSkey;
446 
447 } // namespace lbcrypto
448 
449 #endif
Base class for PALISADE serialization.
Definition: serializable.h:76
Class that stores the refreshing key (used in bootstrapping) A three-dimensional vector of RingGSW ci...
Definition: ringcore.h:361
void SetFormat(const Format format)
Sets the format/representation of the element.
Definition: ilelement.h:451
bool IsPowerOfTwo(usint Input)
Definition: utilities.h:74
void PreCompute()
Definition: ringcore.h:84
Definition: exception.h:147
NativeIntegerT ModMul(const NativeIntegerT &b, const NativeIntegerT &modulus, typename std::enable_if<!std::is_same< T, DNativeInt >::value, bool >::type=true) const
Definition: ubintnat.h:1195
static void PreCompute(const IntType &rootOfUnity, const usint CycloOrder, const IntType &modulus)
Definition: transfrm.cpp:849
Class that stores a RingGSW ciphertext; a two-dimensional vector of ring elements.
Definition: ringcore.h:271
void SetFormat(const Format format)
Definition: ringcore.h:314
OutputType ConvertToInt() const
Definition: ubintnat.h:1886
RingGSWCryptoParams(const std::shared_ptr< LWECryptoParams > lweparams, uint32_t baseG, uint32_t baseR, BINFHEMETHOD method)
Definition: ringcore.h:67
Definition: ringcore.h:440
Definition: binfhecontext.h:36
Main class for big integers represented as an array of native (primitive) unsigned integers...
Definition: backend.h:60
Class that stores all parameters for the RingGSW scheme used in bootstrapping.
Definition: ringcore.h:54
Definition: exception.h:107