PALISADE Lattice Crypto Library  1.11.9
A lattice crypto library for software engineers by software engineers.
ubintnat.h
1 // @file ubintnat.h This file contains the main class for native integers.
2 // @author TPOC: contact@palisade-crypto.org
3 //
4 // @copyright Copyright (c) 2019, New Jersey Institute of Technology (NJIT)
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  * This file contains the main class for native integers.
25  * It implements the same methods as other mathematical backends.
26  */
27 
28 #ifndef LBCRYPTO_MATH_BIGINTNAT_UBINTNAT_H
29 #define LBCRYPTO_MATH_BIGINTNAT_UBINTNAT_H
30 
31 #include <cstdlib>
32 #include <fstream>
33 #include <functional>
34 #include <iostream>
35 #include <limits>
36 #include <memory>
37 #include <sstream>
38 #include <string>
39 #include <type_traits>
40 #include <typeinfo>
41 #include <vector>
42 
43 #include "math/interface.h"
44 #include "math/nbtheory.h"
45 #include "utils/debug.h"
46 #include "utils/exception.h"
47 #include "utils/inttypes.h"
48 #include "utils/memory.h"
49 #include "utils/palisadebase64.h"
50 #include "utils/serializable.h"
51 
52 // the default behavior of the native integer layer is
53 // to assume that the user does not need bounds/range checks
54 // in the native integer code
55 // if you want them, change this #define to true
56 // we use a #define to resolve which to use at compile time
57 // sadly, making the choice according to some setting that
58 // is checked at runtime has awful performance; using this
59 // #define in a simple expression causes the compiler to
60 // optimize away the test
61 #define NATIVEINT_DO_CHECKS false
62 
63 using U32BITS = uint32_t;
64 using U64BITS = uint64_t;
65 #if defined(HAVE_INT128)
66 using U128BITS = unsigned __int128;
67 #endif
68 
69 namespace bigintnat {
70 
71 const double LOG2_10 =
72  3.32192809;
73 
74 const usint BARRETT_LEVELS = 8;
75 
83 template <typename utype>
85  using DoubleType = void;
86  using SignedType = void;
87 };
88 
93 template <>
94 struct DoubleDataType<uint32_t> {
95  using DoubleType = uint64_t;
96  using SignedType = int32_t;
97 };
98 
103 template <>
104 struct DoubleDataType<uint64_t> {
105 #if defined(HAVE_INT128)
106  using DoubleType = __uint128_t;
107 #else
108  using DoubleType = uint64_t;
109 #endif
110  using SignedType = int64_t;
111 };
112 
113 #if defined(HAVE_INT128)
114 template <>
115 struct DoubleDataType<unsigned __int128> {
116  using DoubleType = __uint128_t;
117  using SignedType = __int128;
118 };
119 #endif
120 
126 template <typename NativeInt>
127 class NativeIntegerT
128  : public lbcrypto::BigIntegerInterface<NativeIntegerT<NativeInt>> {
129  public:
130  using Integer = NativeInt;
131  using DNativeInt = typename DoubleDataType<NativeInt>::DoubleType;
132  using SignedNativeInt = typename DoubleDataType<NativeInt>::SignedType;
133 
134  // a data structure to represent a double-word integer as two single-word
135  // integers
136  struct typeD {
137  NativeInt hi = 0;
138  NativeInt lo = 0;
139  inline std::string ConvertToString() {
140  std::string ret("hi [");
141  ret += toString(hi);
142  ret += "], lo [";
143  ret += toString(lo);
144  ret += "]";
145  return ret;
146  }
147  };
148 
150 
154  NativeIntegerT() : m_value(0) {}
155 
161  NativeIntegerT(const NativeIntegerT &val) : m_value(val.m_value) {}
162 
169  : m_value(std::move(val.m_value)) {}
170 
176  NativeIntegerT(const std::string &strval) { AssignVal(strval); }
177 
183  NativeIntegerT(NativeInt val) : m_value(val) {}
184 
189  template <typename T = NativeInt>
190  NativeIntegerT(int16_t init,
191  typename std::enable_if<!std::is_same<T, int16_t>::value,
192  bool>::type = true)
193  : m_value(init) {}
194 
195  template <typename T = NativeInt>
196  NativeIntegerT(uint16_t init,
197  typename std::enable_if<!std::is_same<T, uint16_t>::value,
198  bool>::type = true)
199  : m_value(init) {}
200 
201  template <typename T = NativeInt>
202  NativeIntegerT(int32_t init,
203  typename std::enable_if<!std::is_same<T, int32_t>::value,
204  bool>::type = true)
205  : m_value(init) {}
206 
207  template <typename T = NativeInt>
208  NativeIntegerT(uint32_t init,
209  typename std::enable_if<!std::is_same<T, uint32_t>::value,
210  bool>::type = true)
211  : m_value(init) {}
212 
213  template <typename T = NativeInt>
215  long init,
216  typename std::enable_if<!std::is_same<T, long>::value, bool>::type = true)
217  : m_value(init) {}
218 
219  template <typename T = NativeInt>
220  NativeIntegerT(unsigned long init,
221  typename std::enable_if<!std::is_same<T, unsigned long>::value,
222  bool>::type = true)
223  : m_value(init) {}
224 
225  template <typename T = NativeInt>
226  NativeIntegerT(long long init,
227  typename std::enable_if<!std::is_same<T, long long>::value,
228  bool>::type = true)
229  : m_value(init) {}
230 
231  template <typename T = NativeInt>
233  unsigned long long init,
234  typename std::enable_if<!std::is_same<T, unsigned long long>::value,
235  bool>::type = true)
236  : m_value(init) {}
237 
238 #if defined(HAVE_INT128)
239  template <typename T = NativeInt>
241  unsigned __int128 val,
242  typename std::enable_if<!std::is_same<T, unsigned __int128>::value,
243  bool>::type = true)
244  : m_value(val) {}
245 
246  template <typename T = NativeInt>
247  NativeIntegerT(__int128 val,
248  typename std::enable_if<!std::is_same<T, __int128>::value,
249  bool>::type = true)
250  : m_value(val) {}
251 #endif
252 
259  : m_value(val.ConvertToInt()) {}
260 
266  NativeIntegerT(double val)
267  __attribute__((deprecated("Cannot construct from a double")));
268 
270 
278  this->m_value = val.m_value;
279  return *this;
280  }
281 
289  this->m_value = val.m_value;
290  return *this;
291  }
292 
299  const NativeIntegerT &operator=(const std::string strval) {
300  *this = NativeIntegerT(strval);
301  return *this;
302  }
303 
310  const NativeIntegerT &operator=(const NativeInt &val) {
311  this->m_value = val;
312  return *this;
313  }
314 
315  // ACCESSORS
316 
323  void SetValue(const std::string &strval) { AssignVal(strval); }
324 
331  void SetValue(const NativeIntegerT &val) { m_value = val.m_value; }
332 
337  void SetIdentity() { this->m_value = 1; }
338 
339  // ARITHMETIC OPERATIONS
340 
348  return NATIVEINT_DO_CHECKS ? AddCheck(b) : AddFast(b);
349  }
350 
358  return NATIVEINT_DO_CHECKS ? AddEqCheck(b) : AddEqFast(b);
359  }
360 
369  NativeInt oldv = m_value;
370  m_value += b.m_value;
371  if (m_value < oldv) {
372  PALISADE_THROW(lbcrypto::math_error, "Overflow");
373  }
374  return *this;
375  }
376 
385  m_value += b.m_value;
386  return *this;
387  }
388 
396  return NATIVEINT_DO_CHECKS ? SubCheck(b) : SubFast(b);
397  }
398 
406  return m_value <= b.m_value ? 0 : m_value - b.m_value;
407  }
408 
416  return m_value - b.m_value;
417  }
418 
426  return NATIVEINT_DO_CHECKS ? SubEqCheck(b) : SubEqFast(b);
427  }
428 
437  m_value = m_value <= b.m_value ? 0 : m_value - b.m_value;
438  return *this;
439  }
440 
449  m_value -= b.m_value;
450  return *this;
451  }
452 
453  // overloaded binary operators based on integer arithmetic and comparison
454  // functions.
455  NativeIntegerT operator-() const { return NativeIntegerT(0).Sub(*this); }
456 
464  return NATIVEINT_DO_CHECKS ? MulCheck(b) : MulFast(b);
465  }
466 
474  NativeInt prod = m_value * b.m_value;
475  if (prod > 0 && (prod < m_value || prod < b.m_value))
476  PALISADE_THROW(lbcrypto::math_error, "Overflow");
477  return prod;
478  }
479 
487  return m_value * b.m_value;
488  }
489 
497  return NATIVEINT_DO_CHECKS ? MulEqCheck(b) : MulEqFast(b);
498  }
499 
508  NativeInt oldval = m_value;
509  m_value *= b.m_value;
510  if (m_value < oldval) {
511  PALISADE_THROW(lbcrypto::math_error, "Overflow");
512  }
513  return *this;
514  }
515 
524  m_value *= b.m_value;
525  return *this;
526  }
527 
535  if (b.m_value == 0) PALISADE_THROW(lbcrypto::math_error, "Divide by zero");
536  return this->m_value / b.m_value;
537  }
538 
546  if (b.m_value == 0) PALISADE_THROW(lbcrypto::math_error, "Divide by zero");
547  this->m_value /= b.m_value;
548  return *this;
549  }
550 
557  NativeIntegerT Exp(usint p) const {
558  if (p == 0) {
559  return 1;
560  }
561  if (p == 1) {
562  return NativeIntegerT(*this);
563  }
564  NativeIntegerT tmp = (*this).Exp(p / 2);
565  if (p % 2 == 0) {
566  return tmp * tmp;
567  } else {
568  return tmp * tmp * (*this);
569  }
570  }
571 
578  const NativeIntegerT &ExpEq(usint p) {
579  if (p == 0) {
580  this->m_value = 1;
581  return *this;
582  }
583  if (p == 1) {
584  return *this;
585  }
586  NativeIntegerT tmp = this->Exp(p / 2);
587  if (p % 2 == 0) {
588  *this = (tmp * tmp);
589  return *this;
590  } else {
591  (*this) *= (tmp * tmp);
592  return *this;
593  }
594  }
595 
605  const NativeIntegerT &q) const {
606  NativeIntegerT ans = m_value * p.m_value;
607  return ans.DivideAndRound(q);
608  }
609 
619  const NativeIntegerT &q) {
620  this->MulEq(p);
621  this->DivideAndRoundEq(q);
622  return *this;
623  }
624 
633  template <typename T = NativeInt>
635  const NativeIntegerT &p, const NativeIntegerT &q,
636  typename std::enable_if<!std::is_same<T, DNativeInt>::value, bool>::type =
637  true) const {
638  DNativeInt xD = m_value;
639  DNativeInt pD = p.m_value;
640  DNativeInt qD = q.m_value;
641  return NativeIntegerT(xD * pD / qD);
642  }
643 
644  template <typename T = NativeInt>
645  NativeIntegerT MultiplyAndDivideQuotient(
646  const NativeIntegerT &p, const NativeIntegerT &q,
647  typename std::enable_if<std::is_same<T, DNativeInt>::value, bool>::type =
648  true) const {
649  NativeInt xD = m_value;
650  NativeInt pD = p.m_value;
651  NativeInt qD = q.m_value;
652  return NativeIntegerT(xD * pD / qD);
653  }
654 
663  template <typename T = NativeInt>
665  const NativeIntegerT &p, const NativeIntegerT &q,
666  typename std::enable_if<!std::is_same<T, DNativeInt>::value, bool>::type =
667  true) const {
668  DNativeInt xD = m_value;
669  DNativeInt pD = p.m_value;
670  DNativeInt qD = q.m_value;
671  return NativeIntegerT((xD * pD) % qD);
672  }
673 
674  template <typename T = NativeInt>
675  NativeIntegerT MultiplyAndDivideRemainder(
676  const NativeIntegerT &p, const NativeIntegerT &q,
677  typename std::enable_if<std::is_same<T, DNativeInt>::value, bool>::type =
678  true) const {
679  NativeInt xD = m_value;
680  NativeInt pD = p.m_value;
681  NativeInt qD = q.m_value;
682  return NativeIntegerT((xD * pD) % qD);
683  }
684 
693  if (q == 0) {
694  PALISADE_THROW(lbcrypto::math_error, "Divide by zero");
695  }
696  NativeInt ans = m_value / q.m_value;
697  NativeInt rem = m_value % q.m_value;
698  NativeInt halfQ = q.m_value >> 1;
699  if (!(rem <= halfQ)) {
700  ans += 1;
701  }
702  return ans;
703  }
704 
713  return *this = this->DivideAndRound(q);
714  }
715 
716  // MODULAR ARITHMETIC OPERATIONS
717 
724  NativeIntegerT Mod(const NativeIntegerT &modulus) const {
725  return m_value % modulus.m_value;
726  }
727 
734  const NativeIntegerT &ModEq(const NativeIntegerT &modulus) {
735  m_value %= modulus.m_value;
736  return *this;
737  }
738 
744  template <typename T = NativeInt>
746  typename std::enable_if<!std::is_same<T, DNativeInt>::value, bool>::type =
747  true) const {
748  DNativeInt temp(1);
749  temp <<= 2 * this->GetMSB() + 3;
750  return NativeInt(temp / DNativeInt(this->m_value));
751  }
752 
753  template <typename T = NativeInt>
754  NativeIntegerT ComputeMu(
755  typename std::enable_if<std::is_same<T, DNativeInt>::value, bool>::type =
756  true) const {
757  lbcrypto::BigInteger temp(static_cast<T>(1));
758  temp <<= 2 * this->GetMSB() + 3;
759  return NativeInt((temp / lbcrypto::BigInteger(*this)).ConvertToInt());
760  }
761 
771  template <typename T = NativeInt>
773  const NativeIntegerT &modulus, const NativeIntegerT &mu,
774  typename std::enable_if<!std::is_same<T, DNativeInt>::value, bool>::type =
775  true) const {
776  typeD tmp1;
777  tmp1.lo = this->m_value;
778  tmp1.hi = 0;
779  DNativeInt tmp(this->m_value);
780 
781  long n = modulus.GetMSB();
782  long alpha = n + 3;
783  long beta = -2;
784 
785  // RShiftD is more efficient than the right-shifting of DNativeInt
786  NativeInt ql = RShiftD(tmp1, n + beta);
787  MultD(ql, mu.m_value, tmp1);
788  DNativeInt q = GetD(tmp1);
789 
790  // we cannot use RShiftD here because alpha - beta > 63
791  // for q larger than 57 bits
792  q >>= alpha - beta;
793  tmp -= q * DNativeInt(modulus.m_value);
794 
795  NativeIntegerT ans;
796  ans.m_value = NativeInt(tmp);
797 
798  // correction at the end
799  if (ans.m_value > modulus.m_value) {
800  ans.m_value -= modulus.m_value;
801  }
802  return ans;
803  }
804 
805  template <typename T = NativeInt>
806  NativeIntegerT Mod(const NativeIntegerT &modulus, const NativeIntegerT &mu,
807  typename std::enable_if<std::is_same<T, DNativeInt>::value,
808  bool>::type = true) const {
809  typeD prod;
810  prod.lo = this->m_value;
811  prod.hi = 0;
812  typeD result = prod;
813 
814  long n = modulus.GetMSB();
815  long alpha = n + 3;
816  long beta = -2;
817 
818  NativeInt ql = RShiftD(prod, n + beta);
819  MultD(ql, mu.m_value, prod);
820 
821  ql = RShiftD(prod, alpha - beta);
822  MultD(ql, modulus.m_value, prod);
823  SubtractD(result, prod);
824 
825  NativeIntegerT ans(result.lo);
826  // correction at the end
827  if (ans.m_value > modulus.m_value) {
828  ans.m_value -= modulus.m_value;
829  }
830  return ans;
831  }
832 
842  template <typename T = NativeInt>
844  const NativeIntegerT &modulus, const NativeIntegerT &mu,
845  typename std::enable_if<!std::is_same<T, DNativeInt>::value, bool>::type =
846  true) {
847  typeD tmp1;
848  tmp1.lo = this->m_value;
849  tmp1.hi = 0;
850  DNativeInt tmp(this->m_value);
851 
852  long n = modulus.GetMSB();
853  long alpha = n + 3;
854  long beta = -2;
855 
856  // RShiftD is more efficient than the right-shifting of DNativeInt
857  NativeInt ql = RShiftD(tmp1, n + beta);
858  MultD(ql, mu.m_value, tmp1);
859  DNativeInt q = GetD(tmp1);
860 
861  // we cannot use RShiftD here because alpha - beta > 63
862  // for q larger than 57 bits
863  q >>= alpha - beta;
864  tmp -= q * DNativeInt(modulus.m_value);
865 
866  this->m_value = NativeInt(tmp);
867 
868  // correction at the end
869  if (this->m_value > modulus.m_value) {
870  this->m_value -= modulus.m_value;
871  }
872  return *this;
873  }
874 
875  template <typename T = NativeInt>
876  const NativeIntegerT &ModEq(
877  const NativeIntegerT &modulus, const NativeIntegerT &mu,
878  typename std::enable_if<std::is_same<T, DNativeInt>::value, bool>::type =
879  true) {
880  typeD prod;
881  prod.lo = this->m_value;
882  prod.hi = 0;
883  typeD result = prod;
884 
885  long n = modulus.GetMSB();
886  long alpha = n + 3;
887  long beta = -2;
888 
889  NativeInt ql = RShiftD(prod, n + beta);
890  MultD(ql, mu.m_value, prod);
891 
892  ql = RShiftD(prod, alpha - beta);
893  MultD(ql, modulus.m_value, prod);
894  SubtractD(result, prod);
895 
896  this->m_value = result.lo;
897  // correction at the end
898  if (this->m_value > modulus.m_value) {
899  this->m_value -= modulus.m_value;
900  }
901  return *this;
902  }
903 
912  const NativeIntegerT &modulus) const {
913  NativeInt mod = modulus.m_value;
914  NativeInt op1 = this->m_value;
915  NativeInt op2 = b.m_value;
916  if (op1 >= mod) {
917  op1 %= mod;
918  }
919  if (op2 >= mod) {
920  op2 %= mod;
921  }
922  op1 += op2;
923  if (op1 >= mod) {
924  op1 -= mod;
925  }
926  return op1;
927  }
928 
937  const NativeIntegerT &modulus) {
938  NativeInt mod = modulus.m_value;
939  NativeInt op2 = b.m_value;
940  if (this->m_value >= mod) {
941  this->m_value %= mod;
942  }
943  if (op2 >= mod) {
944  op2 %= mod;
945  }
946  this->m_value += op2;
947  if (this->m_value >= mod) {
948  this->m_value -= mod;
949  }
950  return *this;
951  }
952 
961  const NativeIntegerT &modulus) const {
962  NativeInt r = this->m_value + b.m_value;
963  if (r >= modulus.m_value) {
964  r -= modulus.m_value;
965  }
966  return r;
967  }
976  const NativeIntegerT &modulus) {
977  this->m_value += b.m_value;
978  if (this->m_value >= modulus.m_value) {
979  this->m_value -= modulus.m_value;
980  }
981  return *this;
982  }
983 
993  const NativeIntegerT &mu) const {
994  NativeInt mod(modulus.m_value);
995  NativeIntegerT av(this->m_value);
996  NativeIntegerT bv(b.m_value);
997  if (av.m_value >= mod) {
998  av.ModEq(modulus, mu);
999  }
1000  if (bv.m_value >= mod) {
1001  bv.ModEq(modulus, mu);
1002  }
1003  av.m_value += bv.m_value;
1004  if (av.m_value >= mod) {
1005  av.m_value -= mod;
1006  }
1007  return av;
1008  }
1009 
1019  const NativeIntegerT &modulus,
1020  const NativeIntegerT &mu) {
1021  NativeInt mod(modulus.m_value);
1022  NativeIntegerT bv(b.m_value);
1023  if (this->m_value >= mod) {
1024  this->ModEq(modulus, mu);
1025  }
1026  if (bv.m_value >= mod) {
1027  bv.ModEq(modulus, mu);
1028  }
1029  this->m_value += bv.m_value;
1030  if (this->m_value >= mod) {
1031  this->m_value -= mod;
1032  }
1033  return *this;
1034  }
1035 
1044  const NativeIntegerT &modulus) const {
1045  NativeInt mod(modulus.m_value);
1046  NativeInt av(this->m_value);
1047  NativeInt bv(b.m_value);
1048  // reduce this to a value lower than modulus
1049  if (av >= mod) {
1050  av %= mod;
1051  }
1052  // reduce b to a value lower than modulus
1053  if (bv >= mod) {
1054  bv %= mod;
1055  }
1056 
1057  if (av >= bv) {
1058  av -= bv;
1059  } else {
1060  av += (mod - bv);
1061  }
1062  return av;
1063  }
1064 
1073  const NativeIntegerT &modulus) {
1074  NativeInt mod(modulus.m_value);
1075  NativeInt bv(b.m_value);
1076  // reduce this to a value lower than modulus
1077  if (this->m_value >= mod) {
1078  this->m_value %= mod;
1079  }
1080  // reduce b to a value lower than modulus
1081  if (bv >= mod) {
1082  bv %= mod;
1083  }
1084 
1085  if (this->m_value >= bv) {
1086  this->m_value -= bv;
1087  } else {
1088  this->m_value += (mod - bv);
1089  }
1090  return *this;
1091  }
1092 
1101  const NativeIntegerT &modulus) const {
1102  NativeInt mod(modulus.m_value);
1103  NativeInt av(this->m_value);
1104  NativeInt bv(b.m_value);
1105 
1106  if (av >= bv) {
1107  av -= bv;
1108  } else {
1109  av += (mod - bv);
1110  }
1111  return av;
1112  }
1113 
1122  const NativeIntegerT &modulus) {
1123  if (this->m_value >= b.m_value) {
1124  this->m_value -= b.m_value;
1125  } else {
1126  this->m_value += (modulus.m_value - b.m_value);
1127  }
1128  return *this;
1129  }
1130 
1140  const NativeIntegerT &mu) const {
1141  NativeInt mod(modulus.m_value);
1142  NativeIntegerT av(this->m_value);
1143  NativeIntegerT bv(b.m_value);
1144  if (av.m_value >= mod) {
1145  av.ModEq(modulus, mu);
1146  }
1147  if (bv.m_value >= mod) {
1148  bv.ModEq(modulus, mu);
1149  }
1150 
1151  if (av.m_value >= bv.m_value) {
1152  av.m_value -= bv.m_value;
1153  } else {
1154  av.m_value += (mod - bv.m_value);
1155  }
1156  return av;
1157  }
1158 
1168  const NativeIntegerT &modulus,
1169  const NativeIntegerT &mu) {
1170  NativeIntegerT bv(b.m_value);
1171  NativeInt mod(modulus.m_value);
1172  if (this->m_value >= mod) {
1173  this->ModEq(modulus, mu);
1174  }
1175  if (bv.m_value >= mod) {
1176  bv.ModEq(modulus, mu);
1177  }
1178 
1179  if (this->m_value >= bv.m_value) {
1180  this->m_value -= bv.m_value;
1181  } else {
1182  this->m_value += (mod - bv.m_value);
1183  }
1184  return *this;
1185  }
1186 
1194  template <typename T = NativeInt>
1196  const NativeIntegerT &b, const NativeIntegerT &modulus,
1197  typename std::enable_if<!std::is_same<T, DNativeInt>::value, bool>::type =
1198  true) const {
1199  NativeInt aval = this->m_value;
1200  NativeInt bval = b.m_value;
1201  NativeInt mod = modulus.m_value;
1202  if (aval > mod) {
1203  aval %= mod;
1204  }
1205  if (bval > mod) {
1206  bval %= mod;
1207  }
1208  DNativeInt av(aval);
1209  DNativeInt bv(bval);
1210  DNativeInt result = av * bv;
1211  DNativeInt dmod(mod);
1212  if (result >= dmod) {
1213  result %= dmod;
1214  }
1215  return NativeIntegerT(result);
1216  }
1217 
1218  template <typename T = NativeInt>
1219  NativeIntegerT ModMul(
1220  const NativeIntegerT &b, const NativeIntegerT &modulus,
1221  typename std::enable_if<std::is_same<T, DNativeInt>::value, bool>::type =
1222  true) const {
1223  NativeIntegerT mu(modulus.ComputeMu());
1224  NativeIntegerT a = *this;
1225  NativeIntegerT bW = b;
1226  if (a > modulus) {
1227  a.ModEq(modulus, mu);
1228  }
1229  if (bW > modulus) {
1230  bW.ModEq(modulus, mu);
1231  }
1232  return a.ModMul(bW, modulus, mu);
1233  }
1234 
1242  template <typename T = NativeInt>
1244  const NativeIntegerT &b, const NativeIntegerT &modulus,
1245  typename std::enable_if<!std::is_same<T, DNativeInt>::value, bool>::type =
1246  true) {
1247  NativeInt bval = b.m_value;
1248  NativeInt mod = modulus.m_value;
1249  if (this->m_value > mod) {
1250  this->m_value %= mod;
1251  }
1252  if (bval > mod) {
1253  bval %= mod;
1254  }
1255  DNativeInt av(m_value);
1256  DNativeInt bv(bval);
1257  DNativeInt result = av * bv;
1258  DNativeInt dmod(mod);
1259  if (result >= dmod) {
1260  result %= dmod;
1261  }
1262  *this = NativeIntegerT(result);
1263  return *this;
1264  }
1265 
1266  template <typename T = NativeInt>
1267  const NativeIntegerT &ModMulEq(
1268  const NativeIntegerT &b, const NativeIntegerT &modulus,
1269  typename std::enable_if<std::is_same<T, DNativeInt>::value, bool>::type =
1270  true) {
1271  NativeIntegerT mu(modulus.ComputeMu());
1272  NativeIntegerT bW = b;
1273  if (*this > modulus) {
1274  ModEq(modulus, mu);
1275  }
1276  if (bW > modulus) {
1277  bW.ModEq(modulus, mu);
1278  }
1279  ModMulEq(bW, modulus, mu);
1280  return *this;
1281  }
1282 
1292  const NativeIntegerT &mu) const {
1293  NativeIntegerT ans(*this);
1294  ans.ModMulEq(b, modulus, mu);
1295  return ans;
1296  }
1297 
1306  template <typename T = NativeInt>
1308  const NativeIntegerT &b, const NativeIntegerT &modulus,
1309  const NativeIntegerT &mu,
1310  typename std::enable_if<!std::is_same<T, DNativeInt>::value, bool>::type =
1311  true) {
1312  NativeIntegerT bb(b);
1313 
1314  if (this->m_value > modulus.m_value) {
1315  this->ModEq(modulus, mu);
1316  }
1317  if (bb.m_value > modulus.m_value) {
1318  bb.ModEq(modulus, mu);
1319  }
1320 
1321  typeD prod1;
1322  MultD(this->m_value, b.m_value, prod1);
1323  DNativeInt prod = GetD(prod1);
1324 
1325  long n = modulus.GetMSB();
1326  long alpha = n + 3;
1327  long beta = -2;
1328 
1329  // RShiftD is more efficient than the right-shifting of DNativeInt
1330  NativeInt ql = RShiftD(prod1, n + beta);
1331  MultD(ql, mu.m_value, prod1);
1332  DNativeInt q = GetD(prod1);
1333 
1334  // we cannot use RShiftD here because alpha - beta > 63
1335  // for q larger than 57 bits
1336  q >>= alpha - beta;
1337  prod -= q * DNativeInt(modulus.m_value);
1338 
1339  this->m_value = NativeInt(prod);
1340 
1341  // correction at the end
1342  if (this->m_value > modulus.m_value) {
1343  this->m_value -= modulus.m_value;
1344  }
1345  return *this;
1346  }
1347 
1348  template <typename T = NativeInt>
1349  const NativeIntegerT &ModMulEq(
1350  const NativeIntegerT &b, const NativeIntegerT &modulus,
1351  const NativeIntegerT &mu,
1352  typename std::enable_if<std::is_same<T, DNativeInt>::value, bool>::type =
1353  true) {
1354  NativeIntegerT bb(b);
1355 
1356  if (this->m_value > modulus.m_value) {
1357  this->ModEq(modulus, mu);
1358  }
1359  if (bb.m_value > modulus.m_value) {
1360  bb.ModEq(modulus, mu);
1361  }
1362 
1363  typeD prod1;
1364  MultD(this->m_value, b.m_value, prod1);
1365  typeD prod = prod1;
1366 
1367  long n = modulus.GetMSB();
1368  long alpha = n + 3;
1369  long beta = -2;
1370 
1371  NativeInt ql = RShiftD(prod1, n + beta);
1372  MultD(ql, mu.m_value, prod1);
1373 
1374  typeD q;
1375  ql = RShiftD(prod1, alpha - beta);
1376  MultD(ql, modulus.m_value, q);
1377  SubtractD(prod, q);
1378 
1379  this->m_value = prod.lo;
1380 
1381  // correction at the end
1382  if (this->m_value > modulus.m_value) {
1383  this->m_value -= modulus.m_value;
1384  }
1385  return *this;
1386  }
1387 
1395  template <typename T = NativeInt>
1397  const NativeIntegerT &b, const NativeIntegerT &modulus,
1398  typename std::enable_if<!std::is_same<T, DNativeInt>::value, bool>::type =
1399  true) const {
1400  DNativeInt av(m_value);
1401  DNativeInt bv(b.m_value);
1402  DNativeInt result = av * bv;
1403  DNativeInt mod(modulus.m_value);
1404  if (result >= mod) {
1405  result %= mod;
1406  }
1407  return NativeIntegerT(result);
1408  }
1409 
1410  template <typename T = NativeInt>
1411  NativeIntegerT ModMulFast(
1412  const NativeIntegerT &b, const NativeIntegerT &modulus,
1413  typename std::enable_if<std::is_same<T, DNativeInt>::value, bool>::type =
1414  true) const {
1415  NativeIntegerT mu(modulus.ComputeMu());
1416  NativeIntegerT a = *this;
1417  NativeIntegerT bW = b;
1418  if (a > modulus) {
1419  a.ModEq(modulus, mu);
1420  }
1421  if (bW > modulus) {
1422  bW.ModEq(modulus, mu);
1423  }
1424  return a.ModMulFast(bW, modulus, mu);
1425  }
1426 
1436  const NativeIntegerT &modulus) {
1437  return *this = this->ModMulFast(b, modulus);
1438  }
1439 
1448  /* Source: http://homes.esat.kuleuven.be/~fvercaut/papers/bar_mont.pdf
1449  @article{knezevicspeeding,
1450  title={Speeding Up Barrett and Montgomery Modular Multiplications},
1451  author={Knezevic, Miroslav and Vercauteren, Frederik and Verbauwhede,
1452  Ingrid}
1453  }
1454  We use the Generalized Barrett modular reduction algorithm described in
1455  Algorithm 2 of the Source. The algorithm was originally proposed in J.-F.
1456  Dhem. Modified version of the Barrett algorithm. Technical report, 1994
1457  and described in more detail in the PhD thesis of the author published at
1458  http://users.belgacom.net/dhem/these/these_public.pdf (Section 2.2.4).
1459  We take \alpha equal to n + 3. So in our case, \mu = 2^(n + \alpha) =
1460  2^(2*n + 3). Generally speaking, the value of \alpha should be \ge \gamma
1461  + 1, where \gamma + n is the number of digits in the dividend. We use the
1462  upper bound of dividend assuming that none of the dividends will be larger
1463  than 2^(2*n + 3). The value of \mu is computed by NativeVector::ComputeMu.
1464  */
1465  template <typename T = NativeInt>
1467  const NativeIntegerT &b, const NativeIntegerT &modulus,
1468  const NativeIntegerT &mu,
1469  typename std::enable_if<!std::is_same<T, DNativeInt>::value, bool>::type =
1470  true) const {
1471  NativeIntegerT ans(*this);
1472 
1473  typeD prod1;
1474  MultD(ans.m_value, b.m_value, prod1);
1475  DNativeInt prod = GetD(prod1);
1476  typeD q0(prod1);
1477 
1478  long n = modulus.GetMSB();
1479  long alpha = n + 3;
1480  long beta = -2;
1481 
1482  // RShiftD is more efficient than the right-shifting of DNativeInt
1483  NativeInt ql = RShiftD(q0, n + beta);
1484  MultD(ql, mu.m_value, q0);
1485  DNativeInt q = GetD(q0);
1486 
1487  // we cannot use RShiftD here because alpha - beta > 63
1488  // for q larger than 57 bits
1489  q >>= alpha - beta;
1490  prod -= q * DNativeInt(modulus.m_value);
1491 
1492  ans.m_value = NativeInt(prod);
1493 
1494  // correction at the end
1495  if (ans.m_value > modulus.m_value) {
1496  ans.m_value -= modulus.m_value;
1497  }
1498  return ans;
1499  }
1500 
1501  template <typename T = NativeInt>
1502  NativeIntegerT ModMulFast(
1503  const NativeIntegerT &b, const NativeIntegerT &modulus,
1504  const NativeIntegerT &mu,
1505  typename std::enable_if<std::is_same<T, DNativeInt>::value, bool>::type =
1506  true) const {
1507  NativeIntegerT ans(*this);
1508 
1509  typeD prod1;
1510  MultD(ans.m_value, b.m_value, prod1);
1511  typeD prod = prod1;
1512 
1513  long n = modulus.GetMSB();
1514  long alpha = n + 3;
1515  long beta = -2;
1516 
1517  NativeInt ql = RShiftD(prod1, n + beta);
1518  MultD(ql, mu.m_value, prod1);
1519 
1520  typeD q;
1521  ql = RShiftD(prod1, alpha - beta);
1522  MultD(ql, modulus.m_value, q);
1523  SubtractD(prod, q);
1524 
1525  ans.m_value = prod.lo;
1526 
1527  // correction at the end
1528  if (ans.m_value > modulus.m_value) {
1529  ans.m_value -= modulus.m_value;
1530  }
1531  return ans;
1532  }
1533 
1543  template <typename T = NativeInt>
1545  const NativeIntegerT &b, const NativeIntegerT &modulus,
1546  const NativeIntegerT &mu,
1547  typename std::enable_if<!std::is_same<T, DNativeInt>::value, bool>::type =
1548  true) {
1549  typeD prod1;
1550  MultD(this->m_value, b.m_value, prod1);
1551  DNativeInt prod = GetD(prod1);
1552  typeD q0(prod1);
1553 
1554  long n = modulus.GetMSB();
1555  long alpha = n + 3;
1556  long beta = -2;
1557 
1558  // RShiftD is more efficient than the right-shifting of DNativeInt
1559  NativeInt ql = RShiftD(q0, n + beta);
1560  MultD(ql, mu.m_value, q0);
1561  DNativeInt q = GetD(q0);
1562 
1563  // we cannot use RShiftD here because alpha - beta > 63
1564  // for q larger than 57 bits
1565  q >>= alpha - beta;
1566  prod -= q * DNativeInt(modulus.m_value);
1567 
1568  this->m_value = NativeInt(prod);
1569 
1570  // correction at the end
1571  if (this->m_value > modulus.m_value) {
1572  this->m_value -= modulus.m_value;
1573  }
1574  return *this;
1575  }
1576 
1577  template <typename T = NativeInt>
1578  const NativeIntegerT &ModMulFastEq(
1579  const NativeIntegerT &b, const NativeIntegerT &modulus,
1580  const NativeIntegerT &mu,
1581  typename std::enable_if<std::is_same<T, DNativeInt>::value, bool>::type =
1582  true) {
1583  typeD prod1;
1584  MultD(this->m_value, b.m_value, prod1);
1585  typeD prod = prod1;
1586 
1587  long n = modulus.GetMSB();
1588  long alpha = n + 3;
1589  long beta = -2;
1590 
1591  NativeInt ql = RShiftD(prod1, n + beta);
1592  MultD(ql, mu.m_value, prod1);
1593 
1594  typeD q;
1595  ql = RShiftD(prod1, alpha - beta);
1596  MultD(ql, modulus.m_value, q);
1597  SubtractD(prod, q);
1598 
1599  this->m_value = prod.lo;
1600 
1601  // correction at the end
1602  if (this->m_value > modulus.m_value) {
1603  this->m_value -= modulus.m_value;
1604  }
1605  return *this;
1606  }
1607 
1608  /* The next three subroutines implement the modular multiplication
1609  algorithm for the case when the multiplicand is used multiple times (known
1610  in advance), as in NTT. The algorithm is described in
1611  https://arxiv.org/pdf/1205.2926.pdf (Dave Harvey, FASTER ARITHMETIC FOR
1612  NUMBER-THEORETIC TRANSFORMS). The algorithm is described in lines 5-7 of
1613  Algorithm 2. The algorithm was originally proposed and implemented in NTL
1614  (https://www.shoup.net/ntl/) by Victor Shoup.
1615  */
1616 
1623  template <typename T = NativeInt>
1625  const NativeIntegerT &modulus,
1626  typename std::enable_if<!std::is_same<T, DNativeInt>::value, bool>::type =
1627  true) const {
1628  DNativeInt w = DNativeInt(this->m_value) << MaxBits();
1629  return NativeInt(w / DNativeInt(modulus.m_value));
1630  }
1631 
1632  template <typename T = NativeInt>
1633  NativeIntegerT PrepModMulConst(
1634  const NativeIntegerT &modulus,
1635  typename std::enable_if<std::is_same<T, DNativeInt>::value, bool>::type =
1636  true) const {
1637  lbcrypto::BigInteger w = lbcrypto::BigInteger(m_value) << MaxBits();
1638  return NativeInt(
1639  (w / lbcrypto::BigInteger(modulus.m_value)).ConvertToInt());
1640  }
1641 
1651  const NativeIntegerT &modulus,
1652  const NativeIntegerT &bInv) const {
1653  NativeInt q = MultDHi(this->m_value, bInv.m_value);
1654  NativeInt yprime = this->m_value * b.m_value - q * modulus.m_value;
1655  return SignedNativeInt(yprime) - SignedNativeInt(modulus.m_value) >= 0
1656  ? yprime - modulus.m_value
1657  : yprime;
1658  }
1659 
1670  const NativeIntegerT &modulus,
1671  const NativeIntegerT &bInv) {
1672  NativeInt q = MultDHi(this->m_value, bInv.m_value);
1673  NativeInt yprime = this->m_value * b.m_value - q * modulus.m_value;
1674  this->m_value =
1675  SignedNativeInt(yprime) - SignedNativeInt(modulus.m_value) >= 0
1676  ? yprime - modulus.m_value
1677  : yprime;
1678  return *this;
1679  }
1680 
1688  template <typename T = NativeInt>
1690  const NativeIntegerT &b, const NativeIntegerT &mod,
1691  typename std::enable_if<!std::is_same<T, DNativeInt>::value, bool>::type =
1692  true) const {
1693  DNativeInt exp(b.m_value);
1694  DNativeInt product(1);
1695  DNativeInt modulus(mod.m_value);
1696  DNativeInt mid(m_value % mod.m_value);
1697  const DNativeInt ZERO(0);
1698  const DNativeInt ONE(1);
1699  const DNativeInt TWO(2);
1700 
1701  while (true) {
1702  if (exp % TWO == ONE) {
1703  product = product * mid;
1704  }
1705 
1706  // running product is calculated
1707  if (product >= modulus) {
1708  product = product % modulus;
1709  }
1710 
1711  // divide by 2 and check even to odd to find bit value
1712  exp >>= 1;
1713  if (exp == ZERO) {
1714  break;
1715  }
1716 
1717  // mid calculates mid^2%q
1718  mid = mid * mid;
1719  mid = mid % modulus;
1720  }
1721  return NativeIntegerT(product);
1722  }
1723 
1724  template <typename T = NativeInt>
1725  NativeIntegerT ModExp(
1726  const NativeIntegerT &b, const NativeIntegerT &mod,
1727  typename std::enable_if<std::is_same<T, DNativeInt>::value, bool>::type =
1728  true) const {
1729  NativeInteger mu(mod.ComputeMu());
1730  NativeInteger exp(b.m_value);
1731  NativeInteger product(1);
1732  NativeInteger modulus(mod.m_value);
1733  NativeInteger mid(m_value % mod.m_value);
1734  const NativeInteger ZERO(0);
1735  const NativeInteger ONE(1);
1736  const NativeInteger TWO(2);
1737 
1738  while (true) {
1739  if (exp % TWO == ONE) {
1740  product.ModMulFastEq(mid, modulus, mu);
1741  }
1742 
1743  // divide by 2 and check even to odd to find bit value
1744  exp >>= 1;
1745  if (exp == ZERO) {
1746  break;
1747  }
1748 
1749  mid.ModMulFastEq(mid, modulus, mu);
1750  }
1751 
1752  return NativeIntegerT(product);
1753  }
1754 
1763  const NativeIntegerT &mod) {
1764  *this = ModExp(b, mod);
1765  return *this;
1766  }
1767 
1775  NativeInt modulus = mod.m_value;
1776  NativeInt a = m_value % modulus;
1777  if (a == 0) {
1778  std::string msg = toString(m_value) +
1779  " does not have a ModInverse using " +
1780  toString(modulus);
1781  PALISADE_THROW(lbcrypto::math_error, msg);
1782  }
1783  if (modulus == 1) {
1784  return 0;
1785  }
1786 
1787  SignedNativeInt m0 = modulus;
1788  SignedNativeInt y = 0;
1789  SignedNativeInt x = 1;
1790  while (a > 1) {
1791  // q is quotient
1792  SignedNativeInt q = a / modulus;
1793 
1794  SignedNativeInt t = modulus;
1795  modulus = a % modulus;
1796  a = t;
1797 
1798  // Update y and x
1799  t = y;
1800  y = x - q * y;
1801  x = t;
1802  }
1803 
1804  // Make x positive
1805  if (x < 0) x += m0;
1806 
1807  return NativeInt(x);
1808  }
1809 
1817  *this = ModInverse(mod);
1818  return *this;
1819  }
1820 
1821  // SHIFT OPERATIONS
1822 
1829  NativeIntegerT LShift(usshort shift) const { return m_value << shift; }
1830 
1837  const NativeIntegerT &LShiftEq(usshort shift) {
1838  m_value <<= shift;
1839  return *this;
1840  }
1841 
1848  NativeIntegerT RShift(usshort shift) const { return m_value >> shift; }
1849 
1856  const NativeIntegerT &RShiftEq(usshort shift) {
1857  m_value >>= shift;
1858  return *this;
1859  }
1860 
1861  // COMPARE
1862 
1870  int Compare(const NativeIntegerT &a) const {
1871  if (this->m_value < a.m_value)
1872  return -1;
1873  else if (this->m_value > a.m_value)
1874  return 1;
1875  return 0;
1876  }
1877 
1878  // CONVERTERS
1879 
1885  template <typename OutputType = NativeInt>
1886  OutputType ConvertToInt() const {
1887  if (sizeof(OutputType) < sizeof(m_value))
1888  PALISADE_THROW(lbcrypto::type_error,
1889  "Invalid integer conversion: sizeof(OutputIntType) < "
1890  "sizeof(InputIntType)");
1891  return static_cast<OutputType>(m_value);
1892  }
1893 
1899  double ConvertToDouble() const { return static_cast<double>(m_value); }
1900 
1907  static NativeIntegerT FromBinaryString(const std::string &bitString) {
1908  if (bitString.length() > MaxBits()) {
1909  PALISADE_THROW(lbcrypto::math_error,
1910  "Bit string is too long to fit in a bigintnat");
1911  }
1912  NativeInt v = 0;
1913  for (size_t i = 0; i < bitString.length(); i++) {
1914  int n = bitString[i] - '0';
1915  if (n < 0 || n > 1) {
1916  PALISADE_THROW(lbcrypto::math_error,
1917  "Bit string must contain only 0 or 1");
1918  }
1919  v <<= 1;
1920  v |= n;
1921  }
1922  return v;
1923  }
1924 
1925  // OTHER FUNCTIONS
1926 
1932  usint GetMSB() const { return lbcrypto::GetMSB(this->m_value); }
1933 
1941  usint GetLengthForBase(usint base) const { return GetMSB(); }
1942 
1957  usint GetDigitAtIndexForBase(usint index, usint base) const {
1958  usint DigitLen = ceil(log2(base));
1959  usint digit = 0;
1960  usint newIndex = 1 + (index - 1) * DigitLen;
1961  for (usint i = 1; i < base; i = i * 2) {
1962  digit += GetBitAtIndex(newIndex) * i;
1963  newIndex++;
1964  }
1965  return digit;
1966  }
1967 
1974  uschar GetBitAtIndex(usint index) const {
1975  if (index == 0) {
1976  PALISADE_THROW(lbcrypto::math_error, "Zero index in GetBitAtIndex");
1977  }
1978 
1979  return (m_value >> (index - 1)) & 0x01;
1980  }
1981 
1986  static NativeIntegerT Allocator() { return 0; }
1987 
1988  // STRINGS & STREAMS
1989 
1996  const std::string ToString() const { return toString(m_value); }
1997 
1998  static const std::string IntegerTypeName() { return "UBNATINT"; }
1999 
2007  friend std::ostream &operator<<(std::ostream &os,
2008  const NativeIntegerT &ptr_obj) {
2009  os << ptr_obj.ToString();
2010  return os;
2011  }
2012 
2013  // SERIALIZATION
2014 
2015  template <class Archive, typename T = void>
2016  typename std::enable_if<std::is_same<NativeInt, U64BITS>::value ||
2017  std::is_same<NativeInt, U32BITS>::value,
2018  T>::type
2019  load(Archive &ar, std::uint32_t const version) {
2020  if (version > SerializedVersion()) {
2021  PALISADE_THROW(lbcrypto::deserialize_error,
2022  "serialized object version " + std::to_string(version) +
2023  " is from a later version of the library");
2024  }
2025  ar(::cereal::make_nvp("v", m_value));
2026  }
2027 
2028 #if defined(HAVE_INT128)
2029  template <class Archive>
2030  typename std::enable_if<std::is_same<NativeInt, U128BITS>::value &&
2031  !cereal::traits::is_text_archive<Archive>::value,
2032  void>::type
2033  load(Archive &ar, std::uint32_t const version) {
2034  if (version > SerializedVersion()) {
2035  PALISADE_THROW(lbcrypto::deserialize_error,
2036  "serialized object version " + std::to_string(version) +
2037  " is from a later version of the library");
2038  }
2039  // get an array with 2 unint64_t values for m_value
2040  uint64_t vec[2];
2041  ar(::cereal::binary_data(vec, sizeof(vec))); // 2*8 - size in bytes
2042  m_value = vec[1]; // most significant word
2043  m_value <<= 64;
2044  m_value += vec[0]; // least significant word
2045  }
2046 
2047  template <class Archive>
2048  typename std::enable_if<std::is_same<NativeInt, U128BITS>::value &&
2049  cereal::traits::is_text_archive<Archive>::value,
2050  void>::type
2051  load(Archive &ar, std::uint32_t const version) {
2052  if (version > SerializedVersion()) {
2053  PALISADE_THROW(lbcrypto::deserialize_error,
2054  "serialized object version " + std::to_string(version) +
2055  " is from a later version of the library");
2056  }
2057  // get an array with 2 unint64_t values for m_value
2058  uint64_t vec[2];
2059  ar(::cereal::make_nvp("i", vec));
2060  m_value = vec[1]; // most significant word
2061  m_value <<= 64;
2062  m_value += vec[0]; // least significant word
2063  }
2064 #endif
2065 
2066  template <class Archive, typename T = void>
2067  typename std::enable_if<std::is_same<NativeInt, U64BITS>::value ||
2068  std::is_same<NativeInt, U32BITS>::value,
2069  T>::type
2070  save(Archive &ar, std::uint32_t const version) const {
2071  ar(::cereal::make_nvp("v", m_value));
2072  }
2073 
2074 #if defined(HAVE_INT128)
2075  template <class Archive>
2076  typename std::enable_if<std::is_same<NativeInt, U128BITS>::value &&
2077  !cereal::traits::is_text_archive<Archive>::value,
2078  void>::type
2079  save(Archive &ar, std::uint32_t const version) const {
2080  // save 2 unint64_t values instead of unsigned __int128
2081  constexpr U128BITS mask = (static_cast<U128BITS>(1) << 64) - 1;
2082  uint64_t vec[2];
2083  vec[0] = m_value & mask; // least significant word
2084  vec[1] = m_value >> 64; // most significant word
2085  ar(::cereal::binary_data(vec, sizeof(vec)));
2086  }
2087 
2088  template <class Archive>
2089  typename std::enable_if<std::is_same<NativeInt, U128BITS>::value &&
2090  cereal::traits::is_text_archive<Archive>::value,
2091  void>::type
2092  save(Archive &ar, std::uint32_t const version) const {
2093  // save 2 unint64_t values instead of unsigned __int128
2094  constexpr U128BITS mask = (static_cast<U128BITS>(1) << 64) - 1;
2095  uint64_t vec[2];
2096  vec[0] = m_value & mask; // least significant word
2097  vec[1] = m_value >> 64; // most significant word
2098  ar(::cereal::make_nvp("i", vec));
2099  }
2100 #endif
2101 
2102  std::string SerializedObjectName() const { return "NATInteger"; }
2103 
2104  static uint32_t SerializedVersion() { return 1; }
2105 
2106  static constexpr unsigned MaxBits() { return m_uintBitLength; }
2107 
2108  static bool IsNativeInt() { return true; }
2109 
2110  protected:
2117  void AssignVal(const std::string &str) {
2118  NativeInt test_value = 0;
2119  m_value = 0;
2120  for (size_t i = 0; i < str.length(); i++) {
2121  int v = str[i] - '0';
2122  if (v < 0 || v > 9) {
2123  PALISADE_THROW(lbcrypto::type_error, "String contains a non-digit");
2124  }
2125  m_value *= 10;
2126  m_value += v;
2127 
2128  if (m_value < test_value) {
2129  PALISADE_THROW(
2131  str + " is too large to fit in this native integer object");
2132  }
2133  test_value = m_value;
2134  }
2135  }
2136 
2137  private:
2138  // representation as a
2139  NativeInt m_value;
2140 
2141  // variable to store the bit width of the integral data type.
2142  static constexpr unsigned m_uintBitLength = sizeof(NativeInt) * 8;
2143  // variable to store the maximum value of the integral data type.
2144  static constexpr NativeInt m_uintMax = std::numeric_limits<NativeInt>::max();
2145 
2146  static constexpr NativeInt NATIVEINTMASK = NativeInt(~0);
2147 
2154  inline NativeIntegerT AddCheck(const NativeIntegerT &b) const {
2155  NativeInt newv = m_value + b.m_value;
2156  if (newv < m_value || newv < b.m_value) {
2157  PALISADE_THROW(lbcrypto::math_error, "Overflow");
2158  }
2159  return newv;
2160  }
2161 
2168  inline NativeIntegerT AddFast(const NativeIntegerT &b) const {
2169  return m_value + b.m_value;
2170  }
2171 
2172  // Computes res -= a;
2173  static inline void SubtractD(typeD &res, const typeD &a) {
2174  if (res.lo < a.lo) {
2175  res.lo += m_uintMax + 1 - a.lo;
2176  res.hi--;
2177  } else {
2178  res.lo -= a.lo;
2179  }
2180 
2181  res.hi -= a.hi;
2182  }
2183 
2192  static inline NativeInt RShiftD(const typeD &x, long shift) {
2193  return (x.lo >> shift) | (x.hi << (MaxBits() - shift));
2194  }
2195 
2205  static inline void MultD(U64BITS a, U64BITS b, typeD &res) {
2206 #if defined(__x86_64__)
2207  // clang-format off
2208  __asm__("mulq %[b]"
2209  : [ lo ] "=a"(res.lo), [ hi ] "=d"(res.hi)
2210  : [ a ] "%[lo]"(a), [ b ] "rm"(b)
2211  : "cc");
2212  // clang-format on
2213 #elif defined(__aarch64__)
2214  typeD x;
2215  x.hi = 0;
2216  x.lo = a;
2217  U64BITS y(b);
2218  res.lo = x.lo * y;
2219  asm("umulh %0, %1, %2\n\t" : "=r"(res.hi) : "r"(x.lo), "r"(y));
2220  res.hi += x.hi * y;
2221 #elif defined(__arm__) // 32 bit processor
2222  uint64_t wres(0), wa(a), wb(b);
2223 
2224  wres = wa * wb; // should give us the lower 64 bits of 32*32
2225  res.hi = wres >> 32;
2226  res.lo = (uint32_t)wres & 0xFFFFFFFF;
2227 #elif __riscv
2228  U128BITS wres(0), wa(a), wb(b);
2229  wres = wa * wb; // should give us 128 bits of 64 * 64
2230  res.hi = (uint64_t)(wres >> 64);
2231  res.lo = (uint64_t)wres;
2232 #elif defined(__EMSCRIPTEN__) // web assembly
2233  U64BITS a1 = a >> 32;
2234  U64BITS a2 = (uint32_t)a;
2235  U64BITS b1 = b >> 32;
2236  U64BITS b2 = (uint32_t)b;
2237 
2238  // use schoolbook multiplication
2239  res.hi = a1 * b1;
2240  res.lo = a2 * b2;
2241  U64BITS lowBefore = res.lo;
2242 
2243  U64BITS p1 = a2 * b1;
2244  U64BITS p2 = a1 * b2;
2245  U64BITS temp = p1 + p2;
2246  res.hi += temp >> 32;
2247  res.lo += U64BITS((uint32_t)temp) << 32;
2248 
2249  // adds the carry to the high word
2250  if (lowBefore > res.lo) res.hi++;
2251 
2252  // if there is an overflow in temp, add 2^32
2253  if ((temp < p1) || (temp < p2)) res.hi += (U64BITS)1 << 32;
2254 #else
2255 #error Architecture not supported for MultD()
2256 #endif
2257  }
2258 
2259 #if defined(HAVE_INT128)
2260  static inline void MultD(U128BITS a, U128BITS b, typeD &res) {
2261  // TODO: The performance of this function can be improved
2262  // Instead of 128-bit multiplication, we can use MultD from bigintnat
2263  // We would need to introduce a struct of 4 64-bit integers in this case
2264  U128BITS a1 = a >> 64;
2265  U128BITS a2 = (uint64_t)a;
2266  U128BITS b1 = b >> 64;
2267  U128BITS b2 = (uint64_t)b;
2268 
2269  // use schoolbook multiplication
2270  res.hi = a1 * b1;
2271  res.lo = a2 * b2;
2272  U128BITS lowBefore = res.lo;
2273 
2274  U128BITS p1 = a2 * b1;
2275  U128BITS p2 = a1 * b2;
2276  U128BITS temp = p1 + p2;
2277  res.hi += temp >> 64;
2278  res.lo += U128BITS((uint64_t)temp) << 64;
2279 
2280  // adds the carry to the high word
2281  if (lowBefore > res.lo) res.hi++;
2282 
2283  // if there is an overflow in temp, add 2^64
2284  if ((temp < p1) || (temp < p2)) res.hi += (U128BITS)1 << 64;
2285  }
2286 #endif
2287 
2288  static inline void MultD(U32BITS a, U32BITS b, typeD &res) {
2289  DNativeInt prod = DNativeInt(a) * DNativeInt(b);
2290  res.hi = (prod >> MaxBits()) & NATIVEINTMASK;
2291  res.lo = prod & NATIVEINTMASK;
2292  }
2293 
2302  static inline NativeInt MultDHi(NativeInt a, NativeInt b) {
2303  typeD x;
2304  MultD(a, b, x);
2305  return x.hi;
2306  }
2307 
2315  inline DNativeInt GetD(const typeD &x) const {
2316  return (DNativeInt(x.hi) << MaxBits()) | x.lo;
2317  }
2318 
2319  static inline std::string toString(uint32_t value) {
2320  return std::to_string(value);
2321  }
2322 
2323  static inline std::string toString(uint64_t value) {
2324  return std::to_string(value);
2325  }
2326 
2327 #if defined(HAVE_INT128)
2328  static inline std::string toString(unsigned __int128 value) {
2329  constexpr uint32_t maxChars = 15; // max number of digits/chars we may have
2330  // in every part after division below
2331 
2332  const uint64_t divisor = std::llrint(pow(10, maxChars));
2333  uint64_t part3 = value % divisor;
2334  value /= divisor;
2335  uint64_t part2 = value % divisor;
2336  value /= divisor;
2337  uint64_t part1 = value % divisor;
2338  value /= divisor;
2339 
2340  std::string ret;
2341  ret.reserve(64); // should be more than enough to store the value of a
2342  // 128-bit integer
2343 
2344  bool appendNextPart = false;
2345  if (part1) {
2346  ret = std::to_string(part1);
2347  appendNextPart = true;
2348  }
2349 
2350  if (part2) {
2351  std::string part2str(std::to_string(part2));
2352  if (appendNextPart) {
2353  ret += std::string(maxChars - part2str.size(), '0');
2354  ret += part2str;
2355  } else {
2356  ret = part2str;
2357  appendNextPart = true;
2358  }
2359  } else if (appendNextPart) {
2360  ret += std::string(maxChars, '0'); // add zeroes only
2361  }
2362 
2363  if (part3) {
2364  std::string part3str(std::to_string(part3));
2365  if (appendNextPart) {
2366  ret += std::string(maxChars - part3str.size(), '0');
2367  ret += part3str;
2368  } else {
2369  ret = part3str;
2370  }
2371  } else if (appendNextPart) {
2372  ret += std::string(maxChars, '0');
2373  } else {
2374  ret = "0";
2375  }
2376 
2377  return ret;
2378  /*
2379  * The following implementation doesn't works as fast as the implementation
2380  * above, but is much shorter...:
2381  */
2382  /*
2383  {
2384  // 64 bytes should be more than enough to store the value of a 128-bit
2385  integer
2386  // and we will keep the terminating zero at the buffer end
2387  char retBuff[64] = {0};
2388  char* ptr = &retBuff[63];
2389  while( value ) {
2390  *(--ptr) = '0' + value % 10;
2391  value /= 10;
2392  }
2393  return std::string(ptr);
2394  }
2395  */
2396  }
2397 #endif
2398 };
2399 
2400 } // namespace bigintnat
2401 
2402 #endif // LBCRYPTO_MATH_BIGINTNAT_UBINTNAT_H
const double LOG2_10
A pre-computed constant of Log base 2 of 10.
Definition: ubintnat.h:71
const NativeIntegerT & operator=(const NativeIntegerT &val)
ASSIGNMENT OPERATORS.
Definition: ubintnat.h:277
static NativeIntegerT Allocator()
Definition: ubintnat.h:1986
const NativeIntegerT & MulEq(const NativeIntegerT &b)
Definition: ubintnat.h:496
NativeIntegerT Sub(const NativeIntegerT &b) const
Definition: ubintnat.h:395
NativeIntegerT ModSub(const NativeIntegerT &b, const NativeIntegerT &modulus, const NativeIntegerT &mu) const
Definition: ubintnat.h:1139
NativeIntegerT SubCheck(const NativeIntegerT &b) const
Definition: ubintnat.h:405
Definition: ubintnat.h:136
const NativeIntegerT & ModSubEq(const NativeIntegerT &b, const NativeIntegerT &modulus, const NativeIntegerT &mu)
Definition: ubintnat.h:1167
const NativeIntegerT & ModAddEq(const NativeIntegerT &b, const NativeIntegerT &modulus, const NativeIntegerT &mu)
Definition: ubintnat.h:1018
NativeIntegerT Mul(const NativeIntegerT &b) const
Definition: ubintnat.h:463
const NativeIntegerT & LShiftEq(usshort shift)
Definition: ubintnat.h:1837
const NativeIntegerT & SubEqFast(const NativeIntegerT &b)
Definition: ubintnat.h:448
const NativeIntegerT & ModSubFastEq(const NativeIntegerT &b, const NativeIntegerT &modulus)
Definition: ubintnat.h:1121
const NativeIntegerT & DividedByEq(const NativeIntegerT &b)
Definition: ubintnat.h:545
NativeIntegerT Mod(const NativeIntegerT &modulus, const NativeIntegerT &mu, typename std::enable_if<!std::is_same< T, DNativeInt >::value, bool >::type=true) const
Definition: ubintnat.h:772
const NativeIntegerT & AddEqCheck(const NativeIntegerT &b)
Definition: ubintnat.h:368
const NativeIntegerT & SubEqCheck(const NativeIntegerT &b)
Definition: ubintnat.h:436
usint GetMSB() const
Definition: ubintnat.h:1932
const NativeIntegerT & ModAddEq(const NativeIntegerT &b, const NativeIntegerT &modulus)
Definition: ubintnat.h:936
const NativeIntegerT & MultiplyAndRoundEq(const NativeIntegerT &p, const NativeIntegerT &q)
Definition: ubintnat.h:618
NativeIntegerT(const NativeIntegerT &&val)
Definition: ubintnat.h:168
const NativeIntegerT & ModSubEq(const NativeIntegerT &b, const NativeIntegerT &modulus)
Definition: ubintnat.h:1072
Definition: stl_allocator.h:124
Definition: exception.h:133
NativeIntegerT MultiplyAndDivideQuotient(const NativeIntegerT &p, const NativeIntegerT &q, typename std::enable_if<!std::is_same< T, DNativeInt >::value, bool >::type=true) const
Definition: ubintnat.h:634
const std::string ToString() const
Definition: ubintnat.h:1996
NativeIntegerT Mod(const NativeIntegerT &modulus) const
Definition: ubintnat.h:724
NativeIntegerT ModExp(const NativeIntegerT &b, const NativeIntegerT &mod, typename std::enable_if<!std::is_same< T, DNativeInt >::value, bool >::type=true) const
Definition: ubintnat.h:1689
NativeIntegerT Add(const NativeIntegerT &b) const
Definition: ubintnat.h:347
const NativeIntegerT & MulEqCheck(const NativeIntegerT &b)
Definition: ubintnat.h:507
NativeIntegerT MulFast(const NativeIntegerT &b) const
Definition: ubintnat.h:486
NativeIntegerT LShift(usshort shift) const
Definition: ubintnat.h:1829
uschar GetBitAtIndex(usint index) const
Definition: ubintnat.h:1974
const NativeIntegerT & SubEq(const NativeIntegerT &b)
Definition: ubintnat.h:425
void SetValue(const NativeIntegerT &val)
Definition: ubintnat.h:331
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
NativeIntegerT DivideAndRound(const NativeIntegerT &q) const
Definition: ubintnat.h:692
Definition: exception.h:113
const NativeIntegerT & ModMulFastEq(const NativeIntegerT &b, const NativeIntegerT &modulus)
Definition: ubintnat.h:1435
NativeIntegerT ModSub(const NativeIntegerT &b, const NativeIntegerT &modulus) const
Definition: ubintnat.h:1043
NativeIntegerT ModAdd(const NativeIntegerT &b, const NativeIntegerT &modulus) const
Definition: ubintnat.h:911
NativeIntegerT(int16_t init, typename std::enable_if<!std::is_same< T, int16_t >::value, bool >::type=true)
Definition: ubintnat.h:190
NativeIntegerT ModInverse(const NativeIntegerT &mod) const
Definition: ubintnat.h:1774
const NativeIntegerT & AddEq(const NativeIntegerT &b)
Definition: ubintnat.h:357
usint GetLengthForBase(usint base) const
Definition: ubintnat.h:1941
const NativeIntegerT & operator=(const std::string strval)
Definition: ubintnat.h:299
NativeIntegerT PrepModMulConst(const NativeIntegerT &modulus, typename std::enable_if<!std::is_same< T, DNativeInt >::value, bool >::type=true) const
Definition: ubintnat.h:1624
NativeIntegerT Exp(usint p) const
Definition: ubintnat.h:557
const NativeIntegerT & MulEqFast(const NativeIntegerT &b)
Definition: ubintnat.h:523
NativeIntegerT SubFast(const NativeIntegerT &b) const
Definition: ubintnat.h:415
const NativeIntegerT & ModMulFastConstEq(const NativeIntegerT &b, const NativeIntegerT &modulus, const NativeIntegerT &bInv)
Definition: ubintnat.h:1669
NativeIntegerT ModAddFast(const NativeIntegerT &b, const NativeIntegerT &modulus) const
Definition: ubintnat.h:960
const NativeIntegerT & ModMulFastEq(const NativeIntegerT &b, const NativeIntegerT &modulus, const NativeIntegerT &mu, typename std::enable_if<!std::is_same< T, DNativeInt >::value, bool >::type=true)
Definition: ubintnat.h:1544
const NativeIntegerT & ExpEq(usint p)
Definition: ubintnat.h:578
int Compare(const NativeIntegerT &a) const
Definition: ubintnat.h:1870
Main class for big integers represented as an array of native (primitive) unsigned integers...
Definition: ubintfxd.h:219
const usint BARRETT_LEVELS
The number of levels (precomputed values) used in the Barrett reductions.
Definition: ubintnat.h:74
NativeIntegerT ModSubFast(const NativeIntegerT &b, const NativeIntegerT &modulus) const
Definition: ubintnat.h:1100
const NativeIntegerT & ModInverseEq(const NativeIntegerT &mod)
Definition: ubintnat.h:1816
const NativeIntegerT & ModAddFastEq(const NativeIntegerT &b, const NativeIntegerT &modulus)
Definition: ubintnat.h:975
const NativeIntegerT & ModMulEq(const NativeIntegerT &b, const NativeIntegerT &modulus, typename std::enable_if<!std::is_same< T, DNativeInt >::value, bool >::type=true)
Definition: ubintnat.h:1243
NativeIntegerT ComputeMu(typename std::enable_if<!std::is_same< T, DNativeInt >::value, bool >::type=true) const
Definition: ubintnat.h:745
const NativeIntegerT & DivideAndRoundEq(const NativeIntegerT &q)
Definition: ubintnat.h:712
usint GetDigitAtIndexForBase(usint index, usint base) const
Definition: ubintnat.h:1957
NativeIntegerT ModAdd(const NativeIntegerT &b, const NativeIntegerT &modulus, const NativeIntegerT &mu) const
Definition: ubintnat.h:992
const NativeIntegerT & ModExpEq(const NativeIntegerT &b, const NativeIntegerT &mod)
Definition: ubintnat.h:1762
NativeIntegerT(const lbcrypto::BigInteger &val)
Definition: ubintnat.h:258
NativeIntegerT RShift(usshort shift) const
Definition: ubintnat.h:1848
NativeIntegerT(NativeInt val)
Definition: ubintnat.h:183
const NativeIntegerT & RShiftEq(usshort shift)
Definition: ubintnat.h:1856
void SetValue(const std::string &strval)
Definition: ubintnat.h:323
OutputType ConvertToInt() const
Definition: ubintnat.h:1886
NativeIntegerT ModMulFast(const NativeIntegerT &b, const NativeIntegerT &modulus, typename std::enable_if<!std::is_same< T, DNativeInt >::value, bool >::type=true) const
Definition: ubintnat.h:1396
const NativeIntegerT & operator=(const NativeInt &val)
Definition: ubintnat.h:310
NativeIntegerT(const NativeIntegerT &val)
Definition: ubintnat.h:161
const NativeIntegerT & ModMulEq(const NativeIntegerT &b, const NativeIntegerT &modulus, const NativeIntegerT &mu, typename std::enable_if<!std::is_same< T, DNativeInt >::value, bool >::type=true)
Definition: ubintnat.h:1307
Struct to determine a datatype that is twice as big(bitwise) as utype. sets T as of type void for def...
Definition: ubintnat.h:84
const NativeIntegerT & ModEq(const NativeIntegerT &modulus, const NativeIntegerT &mu, typename std::enable_if<!std::is_same< T, DNativeInt >::value, bool >::type=true)
Definition: ubintnat.h:843
friend std::ostream & operator<<(std::ostream &os, const NativeIntegerT &ptr_obj)
Definition: ubintnat.h:2007
NativeIntegerT(const std::string &strval)
Definition: ubintnat.h:176
const NativeIntegerT & AddEqFast(const NativeIntegerT &b)
Definition: ubintnat.h:384
const NativeIntegerT & ModEq(const NativeIntegerT &modulus)
Definition: ubintnat.h:734
void AssignVal(const std::string &str)
Definition: ubintnat.h:2117
Definition: interface.h:33
void SetIdentity()
Definition: ubintnat.h:337
usint GetMSB(IntType x)
Definition: nbtheory.h:171
NativeIntegerT MultiplyAndRound(const NativeIntegerT &p, const NativeIntegerT &q) const
Definition: ubintnat.h:604
Main class for big integers represented as an array of native (primitive) unsigned integers...
Definition: backend.h:60
NativeIntegerT ModMulFast(const NativeIntegerT &b, const NativeIntegerT &modulus, const NativeIntegerT &mu, typename std::enable_if<!std::is_same< T, DNativeInt >::value, bool >::type=true) const
Definition: ubintnat.h:1466
NativeIntegerT MulCheck(const NativeIntegerT &b) const
Definition: ubintnat.h:473
const NativeIntegerT & operator=(const NativeIntegerT &&val)
Definition: ubintnat.h:288
static NativeIntegerT FromBinaryString(const std::string &bitString)
Definition: ubintnat.h:1907
NativeIntegerT()
CONSTRUCTORS.
Definition: ubintnat.h:154
NativeIntegerT ModMulFastConst(const NativeIntegerT &b, const NativeIntegerT &modulus, const NativeIntegerT &bInv) const
Definition: ubintnat.h:1650
NativeIntegerT ModMul(const NativeIntegerT &b, const NativeIntegerT &modulus, const NativeIntegerT &mu) const
Definition: ubintnat.h:1291
NativeIntegerT DividedBy(const NativeIntegerT &b) const
Definition: ubintnat.h:534
Definition: backend.h:57
double ConvertToDouble() const
Definition: ubintnat.h:1899
NativeIntegerT MultiplyAndDivideRemainder(const NativeIntegerT &p, const NativeIntegerT &q, typename std::enable_if<!std::is_same< T, DNativeInt >::value, bool >::type=true) const
Definition: ubintnat.h:664