Hypercomplex
Abstract & fast header-only C++ template library for lattice-based cryptosystems in high-dimensional algebras
Loading...
Searching...
No Matches
Polynomial.hpp
Go to the documentation of this file.
1// Copyright 2022 <Maciek Bak>
3/*
4###############################################################################
5#
6# Polynomial helper class and functions for the cryptosystems.
7#
8# AUTHOR: Maciek_Bak
9# AFFILIATION: Department_of_Mathematics_City_University_of_London
10# CONTACT: wsciekly.maciek@gmail.com
11# CREATED: 02-12-2022
12# LICENSE: Apache 2.0
13#
14###############################################################################
15*/
16
17// mark that we included this library
18#ifndef HYPERCOMPLEX_POLYNOMIAL_HPP_
19#define HYPERCOMPLEX_POLYNOMIAL_HPP_
20
21#include <cassert>
22#include <iostream>
23
29int64_t RingInverse(const int64_t x, const int64_t mod) {
30 int64_t y = x % mod;
31 if (y < 0) y += mod;
32 for (uint64_t i=1; i < mod; i++) {
33 if ((y*i) % mod == 1) return i;
34 }
35 throw std::invalid_argument("non-invertible element");
36}
37
40template <const uint64_t MaxDeg>
42 private:
43 int64_t* coefficients = new int64_t[MaxDeg+1];
44
45 public:
52 explicit Polynomial(const int64_t* arr) {
53 for (uint64_t i=0; i <= MaxDeg; i++) coefficients[i] = arr[i];
54 }
55
63 for (uint64_t i=0; i <= MaxDeg; i++) coefficients[i] = P[i];
64 }
65
72 for (uint64_t i=0; i <= MaxDeg; i++) coefficients[i] = 0;
73 }
74
75 ~Polynomial() {
76 delete[] coefficients;
77 }
78
84 // self-assignment guard
85 if (this == &P) return *this;
86 // reassign
87 for (uint64_t i=0; i <= MaxDeg; i++) coefficients[i] = P[i];
88 // return the existing object so we can chain this operator
89 return *this;
90 }
91
96 int64_t temparr[MaxDeg+1];
97 for (uint64_t i=0; i <= MaxDeg; i++) temparr[i] = -coefficients[i];
98 Polynomial<MaxDeg> P(temparr);
99 return P;
100 }
101
106 int64_t const & operator[](const uint64_t i) const {
107 assert(0 <= i && i <= MaxDeg);
108 return coefficients[i];
109 }
110
115 int64_t & operator[](const uint64_t i) {
116 assert(0 <= i && i <= MaxDeg);
117 return coefficients[i];
118 }
119};
120
126template <const uint64_t MaxDeg>
128 const Polynomial<MaxDeg> &P1,
129 const Polynomial<MaxDeg> &P2
130) {
131 for (uint64_t i=0; i <= MaxDeg; i++) {
132 if (P1[i] != P2[i]) return false;
133 }
134 return true;
135}
136
142template <const uint64_t MaxDeg>
144 const Polynomial<MaxDeg> &P1,
145 const Polynomial<MaxDeg> &P2
146) {
147 return !(P1 == P2);
148}
149
155template <const uint64_t MaxDeg>
156std::ostream& operator<< (std::ostream &os, const Polynomial<MaxDeg> &P) {
157 for (uint64_t i=0; i < MaxDeg; i++) os << P[i] << ",";
158 os << P[MaxDeg];
159 return os;
160}
161
167template <const uint64_t MaxDeg>
169 int64_t temparr[MaxDeg+1];
170 for (uint64_t i=0; i <= MaxDeg; i++) temparr[i] = P[i] * x;
171 Polynomial<MaxDeg> p(temparr);
172 return p;
173}
174
180template <const uint64_t MaxDeg>
182 const Polynomial<MaxDeg> &P1,
183 const Polynomial<MaxDeg> &P2
184) {
185 int64_t temparr[MaxDeg+1];
186 for (uint64_t i=0; i <= MaxDeg; i++) temparr[i] = P1[i] + P2[i];
187 Polynomial<MaxDeg> p(temparr);
188 return p;
189}
190
196template <const uint64_t MaxDeg>
198 const Polynomial<MaxDeg> &P1,
199 const Polynomial<MaxDeg> &P2
200) {
201 int64_t temparr[MaxDeg+1];
202 for (uint64_t i=0; i <= MaxDeg; i++) temparr[i] = P1[i] - P2[i];
203 Polynomial<MaxDeg> p(temparr);
204 return p;
205}
206
212template <const uint64_t MaxDeg>
214 const Polynomial<MaxDeg> &P1,
215 const Polynomial<MaxDeg> &P2
216) {
217 int64_t prod[2*MaxDeg+1];
218 int64_t conv[MaxDeg+1];
219 for (uint64_t i=0; i < 2*MaxDeg+1; i++) prod[i] = 0;
220 for (uint64_t i=0; i <= MaxDeg; i++) conv[i] = 0;
221 for (uint64_t i=0; i <= MaxDeg; i++) {
222 for (uint64_t j=0; j <= MaxDeg; j++)
223 prod[i+j] += P1[i]*P2[j];
224 }
225 for (uint64_t i=0; i < 2*MaxDeg+1; i++) conv[i%(MaxDeg+1)] += prod[i];
226 Polynomial<MaxDeg> p(conv);
227 return p;
228}
229
235template <const uint64_t MaxDeg>
237 int64_t temparr[MaxDeg+1];
238 for (uint64_t i=0; i <= MaxDeg; i++) {
239 temparr[i] = P[i] % x;
240 if (temparr[i] < 0) temparr[i] += x;
241 }
242 Polynomial<MaxDeg> p(temparr);
243 return p;
244}
245
250template <const uint64_t MaxDeg>
251void CenteredLift(Polynomial<MaxDeg> *P, const int64_t mod) {
252 int64_t lower = -mod/2;
253 int64_t upper = mod/2;
254 for (uint64_t i = 0; i <= MaxDeg; i++) {
255 if (mod % 2) { // odd: <lower, upper>
256 if ((*P)[i] < lower) (*P)[i] = (*P)[i] + mod;
257 if ((*P)[i] > upper) (*P)[i] = (*P)[i] - mod;
258 } else { // even: (lower, upper>
259 if ((*P)[i] <= lower) (*P)[i] = (*P)[i] + mod;
260 if ((*P)[i] > upper) (*P)[i] = (*P)[i] - mod;
261 }
262 }
263}
264
270template <const uint64_t MaxDeg>
272 const Polynomial<MaxDeg> &P,
273 const int64_t &mod
274) {
275 // make sure to shift coefficients to: [0,mod-1]
276 Polynomial<MaxDeg> P_ = P % mod;
277 //
278 // define placeholders & init values
279 //
282 //
285 newt[0] = 1;
286 //
288 r[0] = mod-1;
289 r[MaxDeg+1] = 1;
290 uint64_t deg_r = MaxDeg+1;
291 for (uint64_t i=0; i <= MaxDeg; i++) temp[i] = P_[i];
292 Polynomial<MaxDeg+1> newr(temp);
293 uint64_t deg_newr = 0;
294 for (uint64_t i=0; i <= MaxDeg+1; i++) {
295 if (newr[i]) deg_newr = i;
296 }
297
298 // algorithm loop
299 while (deg_newr > 0) {
300 // division loop
301 while (deg_r >= deg_newr) {
302 for (uint64_t i=0; i <= MaxDeg+1; i++) temp[i] = 0;
303 for (uint64_t i=0; i <= deg_newr; i++)
304 temp[i + deg_r - deg_newr] = newr[i];
305 q[deg_r - deg_newr] =
306 (r[deg_r] * RingInverse(temp[deg_r], mod)) % mod;
307 for (uint64_t i=0; i <= deg_r; i++)
308 temp[i] = (temp[i] * q[deg_r - deg_newr]) % mod;
309 temp = temp % mod;
310 for (uint64_t i=0; i <= deg_r; i++) r[i] = r[i] - temp[i];
311 r = r % mod;
312 deg_r -= 1;
313 }
314
315 // re-assign labels after one round of the algorithm:
316 temp = newr;
317 newr = r;
318 r = temp;
319 //
320 temp = newt;
321 newt = (t - (q * newt)) % mod;
322 t = temp;
323
324 // reset variables:
325 for (uint64_t i=0; i <= MaxDeg+1; i++) q[i] = 0;
326 for (uint64_t i=0; i <= MaxDeg+1; i++) {
327 if (newr[i]) deg_newr = i;
328 }
329 for (uint64_t i=0; i <= MaxDeg+1; i++) {
330 if (r[i]) deg_r = i;
331 }
332 }
333
334 // after the algorithm: deg of the last remainder < deg(P)
335 assert(newr[MaxDeg+1] == 0);
336
337 // construct the inverse polynomial
338 int64_t multiplier = RingInverse(newr[0], mod);
339 Polynomial<MaxDeg> inverse;
340 for (uint64_t i=0; i <= MaxDeg; i++) inverse[i] = newt[i];
341 inverse = (multiplier * inverse) % mod;
342
343 // test: P * 1/P == 1
344 Polynomial<MaxDeg> unity;
345 unity[0] = 1;
346 assert((inverse * P) % mod == unity);
347
348 return inverse;
349}
350
351#endif // HYPERCOMPLEX_POLYNOMIAL_HPP_
std::ostream & operator<<(std::ostream &os, const Polynomial< MaxDeg > &P)
Print operator.
Definition: Polynomial.hpp:156
int64_t RingInverse(const int64_t x, const int64_t mod)
Integer multiplicative inverse in a modular ring.
Definition: Polynomial.hpp:29
Polynomial< MaxDeg > operator-(const Polynomial< MaxDeg > &P1, const Polynomial< MaxDeg > &P2)
Subtraction operator.
Definition: Polynomial.hpp:197
Polynomial< MaxDeg > operator+(const Polynomial< MaxDeg > &P1, const Polynomial< MaxDeg > &P2)
Addition operator.
Definition: Polynomial.hpp:181
void CenteredLift(Polynomial< MaxDeg > *P, const int64_t mod)
Center-lift polynomial in a modular quotient ring.
Definition: Polynomial.hpp:251
bool operator!=(const Polynomial< MaxDeg > &P1, const Polynomial< MaxDeg > &P2)
Inequality operator.
Definition: Polynomial.hpp:143
bool operator==(const Polynomial< MaxDeg > &P1, const Polynomial< MaxDeg > &P2)
Equality operator.
Definition: Polynomial.hpp:127
Polynomial< MaxDeg > operator*(const int64_t x, const Polynomial< MaxDeg > &P)
Multiplication-by-scalar operator.
Definition: Polynomial.hpp:168
Polynomial< MaxDeg > operator%(const Polynomial< MaxDeg > &P, const int64_t x)
Coefficient reduction modulo a scalar.
Definition: Polynomial.hpp:236
Definition: Polynomial.hpp:41
Polynomial()
This is the default constructor.
Definition: Polynomial.hpp:71
Polynomial operator-() const
Create an additive inverse of a given polynomial.
Definition: Polynomial.hpp:95
Polynomial(const Polynomial &P)
This is the copy constructor.
Definition: Polynomial.hpp:62
Polynomial(const int64_t *arr)
This is the main constructor.
Definition: Polynomial.hpp:52
int64_t const & operator[](const uint64_t i) const
Access operator (const)
Definition: Polynomial.hpp:106
Polynomial & operator=(const Polynomial &P)
Assignment operator.
Definition: Polynomial.hpp:83
int64_t & operator[](const uint64_t i)
Access operator (non-const)
Definition: Polynomial.hpp:115