Intel HEXL
Intel Homomorphic Encryption Acceleration Library, accelerating the modular arithmetic operations used in homomorphic encryption.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
number-theory.hpp
Go to the documentation of this file.
1 // Copyright (C) 2020-2021 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 
4 #pragma once
5 
6 #include <stdint.h>
7 
8 #include <iostream>
9 #include <limits>
10 #include <vector>
11 
12 #include "hexl/util/check.hpp"
13 #include "hexl/util/compiler.hpp"
14 
15 namespace intel {
16 namespace hexl {
17 
21  public:
22  MultiplyFactor() = default;
23 
30  MultiplyFactor(uint64_t operand, uint64_t bit_shift, uint64_t modulus)
31  : m_operand(operand) {
32  HEXL_CHECK(operand <= modulus, "operand " << operand
33  << " must be less than modulus "
34  << modulus);
35  HEXL_CHECK(bit_shift == 32 || bit_shift == 52 || bit_shift == 64,
36  "Unsupported BitShift " << bit_shift);
37  uint64_t op_hi = operand >> (64 - bit_shift);
38  uint64_t op_lo = (bit_shift == 64) ? 0 : (operand << bit_shift);
39 
40  m_barrett_factor = DivideUInt128UInt64Lo(op_hi, op_lo, modulus);
41  }
42 
44  inline uint64_t BarrettFactor() const { return m_barrett_factor; }
45 
47  inline uint64_t Operand() const { return m_operand; }
48 
49  private:
50  uint64_t m_operand;
51  uint64_t m_barrett_factor;
52 };
53 
55 inline bool IsPowerOfTwo(uint64_t num) { return num && !(num & (num - 1)); }
56 
58 inline uint64_t Log2(uint64_t x) { return MSB(x); }
59 
60 inline bool IsPowerOfFour(uint64_t num) {
61  return IsPowerOfTwo(num) && (Log2(num) % 2 == 0);
62 }
63 
65 inline uint64_t MaximumValue(uint64_t bits) {
66  HEXL_CHECK(bits <= 64, "MaximumValue requires bits <= 64; got " << bits);
67  if (bits == 64) {
68  return (std::numeric_limits<uint64_t>::max)();
69  }
70  return (1ULL << bits) - 1;
71 }
72 
77 uint64_t ReverseBits(uint64_t x, uint64_t bit_width);
78 
81 uint64_t InverseMod(uint64_t x, uint64_t modulus);
82 
85 uint64_t MultiplyMod(uint64_t x, uint64_t y, uint64_t modulus);
86 
92 uint64_t MultiplyMod(uint64_t x, uint64_t y, uint64_t y_precon,
93  uint64_t modulus);
94 
97 uint64_t AddUIntMod(uint64_t x, uint64_t y, uint64_t modulus);
98 
101 uint64_t SubUIntMod(uint64_t x, uint64_t y, uint64_t modulus);
102 
104 uint64_t PowMod(uint64_t base, uint64_t exp, uint64_t modulus);
105 
110 bool IsPrimitiveRoot(uint64_t root, uint64_t degree, uint64_t modulus);
111 
114 uint64_t GeneratePrimitiveRoot(uint64_t degree, uint64_t modulus);
115 
119 uint64_t MinimalPrimitiveRoot(uint64_t degree, uint64_t modulus);
120 
128 template <int BitShift>
129 inline uint64_t MultiplyModLazy(uint64_t x, uint64_t y_operand,
130  uint64_t y_barrett_factor, uint64_t modulus) {
131  HEXL_CHECK(y_operand < modulus, "y_operand " << y_operand
132  << " must be less than modulus "
133  << modulus);
134  HEXL_CHECK(
135  modulus <= MaximumValue(BitShift),
136  "Modulus " << modulus << " exceeds bound " << MaximumValue(BitShift));
137  HEXL_CHECK(x <= MaximumValue(BitShift),
138  "Operand " << x << " exceeds bound " << MaximumValue(BitShift));
139 
140  uint64_t Q = MultiplyUInt64Hi<BitShift>(x, y_barrett_factor);
141  return y_operand * x - Q * modulus;
142 }
143 
149 template <int BitShift>
150 inline uint64_t MultiplyModLazy(uint64_t x, uint64_t y, uint64_t modulus) {
151  HEXL_CHECK(BitShift == 64 || BitShift == 52,
152  "Unsupported BitShift " << BitShift);
153  HEXL_CHECK(x <= MaximumValue(BitShift),
154  "Operand " << x << " exceeds bound " << MaximumValue(BitShift));
155  HEXL_CHECK(y < modulus,
156  "y " << y << " must be less than modulus " << modulus);
157  HEXL_CHECK(
158  modulus <= MaximumValue(BitShift),
159  "Modulus " << modulus << " exceeds bound " << MaximumValue(BitShift));
160 
161  uint64_t y_barrett = MultiplyFactor(y, BitShift, modulus).BarrettFactor();
162  return MultiplyModLazy<BitShift>(x, y, y_barrett, modulus);
163 }
164 
170 inline unsigned char AddUInt64(uint64_t operand1, uint64_t operand2,
171  uint64_t* result) {
172  *result = operand1 + operand2;
173  return static_cast<unsigned char>(*result < operand1);
174 }
175 
177 bool IsPrime(uint64_t n);
178 
180 // 2^(bit_size+1)]. Ensures each prime q satisfies
181 // q % (2*ntt_size+1)) == 1
188 std::vector<uint64_t> GeneratePrimes(size_t num_primes, size_t bit_size,
189  bool prefer_small_primes,
190  size_t ntt_size = 1);
191 
196 uint64_t BarrettReduce64(uint64_t input, uint64_t modulus, uint64_t q_barr);
197 
205 template <int InputModFactor>
206 uint64_t ReduceMod(uint64_t x, uint64_t modulus,
207  const uint64_t* twice_modulus = nullptr,
208  const uint64_t* four_times_modulus = nullptr) {
209  HEXL_CHECK(InputModFactor == 1 || InputModFactor == 2 ||
210  InputModFactor == 4 || InputModFactor == 8,
211  "InputModFactor should be 1, 2, 4, or 8");
212  if (InputModFactor == 1) {
213  return x;
214  }
215  if (InputModFactor == 2) {
216  if (x >= modulus) {
217  x -= modulus;
218  }
219  return x;
220  }
221  if (InputModFactor == 4) {
222  HEXL_CHECK(twice_modulus != nullptr, "twice_modulus should not be nullptr");
223  if (x >= *twice_modulus) {
224  x -= *twice_modulus;
225  }
226  if (x >= modulus) {
227  x -= modulus;
228  }
229  return x;
230  }
231  if (InputModFactor == 8) {
232  HEXL_CHECK(twice_modulus != nullptr, "twice_modulus should not be nullptr");
233  HEXL_CHECK(four_times_modulus != nullptr,
234  "four_times_modulus should not be nullptr");
235 
236  if (x >= *four_times_modulus) {
237  x -= *four_times_modulus;
238  }
239  if (x >= *twice_modulus) {
240  x -= *twice_modulus;
241  }
242  if (x >= modulus) {
243  x -= modulus;
244  }
245  return x;
246  }
247  HEXL_CHECK(false, "Should be unreachable");
248  return x;
249 }
250 
251 } // namespace hexl
252 } // namespace intel
uint64_t ReduceMod(uint64_t x, uint64_t modulus, const uint64_t *twice_modulus=nullptr, const uint64_t *four_times_modulus=nullptr)
Returns x mod modulus, assuming x < InputModFactor * modulus.
Definition: number-theory.hpp:206
uint64_t GeneratePrimitiveRoot(uint64_t degree, uint64_t modulus)
Tries to return a primitive degree-th root of unity.
uint64_t MultiplyMod(uint64_t x, uint64_t y, uint64_t modulus)
Returns (x * y) mod modulus.
uint64_t MaximumValue(uint64_t bits)
Returns the maximum value that can be represented using bits bits.
Definition: number-theory.hpp:65
std::vector< uint64_t > GeneratePrimes(size_t num_primes, size_t bit_size, bool prefer_small_primes, size_t ntt_size=1)
Generates a list of num_primes primes in the range [2^(bit_size),.
uint64_t MultiplyModLazy(uint64_t x, uint64_t y_operand, uint64_t y_barrett_factor, uint64_t modulus)
Computes (x * y) mod modulus, except that the output is in [0, 2 * modulus].
Definition: number-theory.hpp:129
MultiplyFactor(uint64_t operand, uint64_t bit_shift, uint64_t modulus)
Computes and stores the Barrett factor floor((operand << bit_shift) / modulus). This is useful when m...
Definition: number-theory.hpp:30
uint64_t SubUIntMod(uint64_t x, uint64_t y, uint64_t modulus)
Returns (x - y) mod modulus.
unsigned char AddUInt64(uint64_t operand1, uint64_t operand2, uint64_t *result)
Adds two unsigned 64-bit integers.
Definition: number-theory.hpp:170
uint64_t BarrettFactor() const
Returns the pre-computed Barrett factor.
Definition: number-theory.hpp:44
bool IsPrime(uint64_t n)
Returns whether or not the input is prime.
bool IsPowerOfTwo(uint64_t num)
Returns whether or not num is a power of two.
Definition: number-theory.hpp:55
#define HEXL_CHECK(cond, expr)
Definition: check.hpp:39
Pre-computes a Barrett factor with which modular multiplication can be performed more efficiently...
Definition: number-theory.hpp:20
Definition: eltwise-add-mod.hpp:8
uint64_t AddUIntMod(uint64_t x, uint64_t y, uint64_t modulus)
Returns (x + y) mod modulus.
uint64_t ReverseBits(uint64_t x, uint64_t bit_width)
Reverses the bits.
bool IsPowerOfFour(uint64_t num)
Definition: number-theory.hpp:60
uint64_t InverseMod(uint64_t x, uint64_t modulus)
Returns x^{-1} mod modulus.
bool IsPrimitiveRoot(uint64_t root, uint64_t degree, uint64_t modulus)
Returns whether or not root is a degree-th root of unity mod modulus.
uint64_t MinimalPrimitiveRoot(uint64_t degree, uint64_t modulus)
Returns whether or not root is a degree-th root of unity.
uint64_t PowMod(uint64_t base, uint64_t exp, uint64_t modulus)
Returns base^exp mod modulus.
uint64_t Operand() const
Returns the operand corresponding to the Barrett factor.
Definition: number-theory.hpp:47
uint64_t BarrettReduce64(uint64_t input, uint64_t modulus, uint64_t q_barr)
Returns input mod modulus, computed via 64-bit Barrett reduction.
uint64_t Log2(uint64_t x)
Returns floor(log2(x))
Definition: number-theory.hpp:58