Botan 3.13.0
Crypto and TLS for C&
polyn_gf2m.cpp
Go to the documentation of this file.
1/*
2 * (C) Copyright Projet SECRET, INRIA, Rocquencourt
3 * (C) Bhaskar Biswas and Nicolas Sendrier
4 *
5 * (C) 2014 cryptosource GmbH
6 * (C) 2014 Falko Strenzke fstrenzke@cryptosource.de
7 * (C) 2015 Jack Lloyd
8 *
9 * Botan is released under the Simplified BSD License (see license.txt)
10 *
11 */
12
13#include <botan/internal/polyn_gf2m.h>
14
15#include <botan/exceptn.h>
16#include <botan/rng.h>
17#include <botan/internal/code_based_util.h>
18#include <botan/internal/loadstor.h>
19
20namespace Botan {
21
22// NOLINTBEGIN(*-implicit-bool-conversion)
23
24namespace {
25
26gf2m generate_gf2m_mask(gf2m a) {
27 const gf2m result = (a != 0);
28 return ~(result - 1);
29}
30
31/**
32* number of leading zeros
33*/
34unsigned nlz_16bit(uint16_t x) {
35 if(x == 0) {
36 return 16;
37 }
38 unsigned n = 0;
39 if(x <= 0x00FF) {
40 n = n + 8;
41 x = x << 8;
42 }
43 if(x <= 0x0FFF) {
44 n = n + 4;
45 x = x << 4;
46 }
47 if(x <= 0x3FFF) {
48 n = n + 2;
49 x = x << 2;
50 }
51 if(x <= 0x7FFF) {
52 n = n + 1;
53 }
54 return n;
55}
56
57} // namespace
58
60 int i = static_cast<int>(this->m_coeff.size()) - 1;
61 int result = 0;
62 uint32_t found_mask = 0;
63 uint32_t tracker_mask = 0xffff;
64 for(; i >= 0; i--) {
65 found_mask = expand_mask_16bit(this->m_coeff[i]);
66 result |= i & found_mask & tracker_mask;
67 // tracker mask shall become zero once found mask is set
68 // it shall remain zero from then on
69 tracker_mask = tracker_mask & ~found_mask;
70 }
71 const_cast<polyn_gf2m*>(this)->m_deg = result;
72 return result;
73}
74
76 uint8_t b[2];
77 rng.randomize(b, sizeof(b));
78 return make_uint16(b[1], b[0]);
79}
80
81gf2m random_code_element(uint16_t code_length, RandomNumberGenerator& rng) {
82 if(code_length == 0) {
83 throw Invalid_Argument("random_code_element() was supplied a code length of zero");
84 }
85 const unsigned nlz = nlz_16bit(code_length - 1);
86 const gf2m mask = (1 << (16 - nlz)) - 1;
87
88 gf2m result = random_gf2m(rng) & mask;
89
90 while(result >= code_length) {
91 // rejection sampling
92 result = random_gf2m(rng) & mask;
93 }
94
95 return result;
96}
97
98polyn_gf2m::polyn_gf2m(const polyn_gf2m& other) = default;
99
100polyn_gf2m::polyn_gf2m(int d, const std::shared_ptr<GF2m_Field>& sp_field) : m_deg(-1), m_sp_field(sp_field) {
101 if(d < 0) {
102 throw Invalid_Argument("invalid polynomial degree");
103 }
104 m_coeff.resize(d + 1);
105}
106
107/**
108* doesn't save coefficients:
109*/
110void polyn_gf2m::realloc(uint32_t new_size) {
111 this->m_coeff = secure_vector<gf2m>(new_size);
112}
113
114polyn_gf2m::polyn_gf2m(const uint8_t* mem, uint32_t mem_len, const std::shared_ptr<GF2m_Field>& sp_field) :
115 m_deg(-1), m_sp_field(sp_field) {
116 if(!sp_field) {
117 throw Decoding_Error("missing field for polynomial decoding");
118 }
119
120 if(mem_len % sizeof(gf2m)) {
121 throw Decoding_Error("illegal length of memory to decode ");
122 }
123
124 const uint32_t size = (mem_len / sizeof(this->m_coeff[0]));
125 this->m_coeff = secure_vector<gf2m>(size);
126 this->m_deg = -1;
127 for(uint32_t i = 0; i < size; i++) {
128 this->m_coeff[i] = decode_gf2m(mem);
129 mem += sizeof(this->m_coeff[0]);
130 }
131 for(uint32_t i = 0; i < size; i++) {
132 if(this->m_coeff[i] >= (static_cast<size_t>(1) << sp_field->get_extension_degree())) {
133 throw Decoding_Error("error decoding polynomial");
134 }
135 }
136 this->get_degree();
137}
138
139polyn_gf2m::polyn_gf2m(const std::shared_ptr<GF2m_Field>& sp_field) : m_deg(-1), m_coeff(1), m_sp_field(sp_field) {}
140
142 const uint8_t* mem,
143 size_t mem_byte_len,
144 const std::shared_ptr<GF2m_Field>& sp_field) :
145 m_sp_field(sp_field) {
146 if(!sp_field) {
147 throw Decoding_Error("missing field for polynomial decoding");
148 }
149
150 if(degree < 0) {
151 throw Decoding_Error("invalid polynomial degree");
152 }
153
154 const uint32_t polyn_size = degree + 1;
155 if(polyn_size * sp_field->get_extension_degree() > 8 * mem_byte_len) {
156 throw Decoding_Error("memory vector for polynomial has wrong size");
157 }
158 this->m_coeff = secure_vector<gf2m>(degree + 1);
159 const gf2m ext_deg = static_cast<gf2m>(this->m_sp_field->get_extension_degree());
160 for(uint32_t l = 0; l < polyn_size; l++) {
161 const uint32_t k = (l * ext_deg) / 8;
162
163 const uint32_t j = (l * ext_deg) % 8;
164 gf2m a = mem[k] >> j;
165 if(j + ext_deg > 8) {
166 a ^= mem[k + 1] << (8 - j);
167 }
168 if(j + ext_deg > 16) {
169 a ^= mem[k + 2] << (16 - j);
170 }
171 a &= ((1 << ext_deg) - 1);
172 (*this).set_coef(l, a);
173 }
174
175 this->get_degree();
176}
177
179 clear_mem(this->m_coeff.data(), this->m_coeff.size());
180 this->m_deg = -1;
181}
182
184 int d = static_cast<int>(this->m_coeff.size()) - 1;
185 while((d >= 0) && (this->m_coeff[d] == 0)) {
186 --d;
187 }
188 const_cast<polyn_gf2m*>(this)->m_deg = d;
189 return d;
190}
191
192namespace {
193
194gf2m eval_aux(const gf2m* /*restrict*/ coeff, gf2m a, int d, const std::shared_ptr<GF2m_Field>& sp_field) {
195 gf2m b = coeff[d--];
196 for(; d >= 0; --d) {
197 if(b != 0) {
198 b = sp_field->gf_mul(b, a) ^ coeff[d];
199 } else {
200 b = coeff[d];
201 }
202 }
203 return b;
204}
205
206} // namespace
207
209 return eval_aux(this->m_coeff.data(), a, this->m_deg, this->m_sp_field);
210}
211
212// p will contain it's remainder modulo g
213void polyn_gf2m::remainder(polyn_gf2m& p, const polyn_gf2m& g) {
214 int i = 0;
215 int j = 0;
216 const std::shared_ptr<GF2m_Field> m_sp_field = g.m_sp_field;
217 int d = p.get_degree() - g.get_degree();
218 if(d >= 0) {
219 const gf2m la = m_sp_field->gf_inv_rn(g.get_lead_coef());
220
221 const int p_degree = p.get_degree();
222
223 BOTAN_ASSERT(p_degree > 0, "Valid polynomial");
224
225 for(i = p_degree; d >= 0; --i, --d) {
226 if(p[i] != 0) {
227 const gf2m lb = m_sp_field->gf_mul_rrn(la, p[i]);
228 for(j = 0; j < g.get_degree(); ++j) {
229 p[j + d] ^= m_sp_field->gf_mul_zrz(lb, g[j]);
230 }
231 (*&p).set_coef(i, 0);
232 }
233 }
234 p.set_degree(g.get_degree() - 1);
235 while((p.get_degree() >= 0) && (p[p.get_degree()] == 0)) {
236 p.set_degree(p.get_degree() - 1);
237 }
238 }
239}
240
241std::vector<polyn_gf2m> polyn_gf2m::sqmod_init(const polyn_gf2m& g) {
242 std::vector<polyn_gf2m> sq;
243 const int signed_deg = g.get_degree();
244 if(signed_deg <= 0) {
245 throw Invalid_Argument("cannot compute sqmod for such low degree");
246 }
247
248 const uint32_t d = static_cast<uint32_t>(signed_deg);
249 const uint32_t t = g.m_deg;
250 // create t zero polynomials
251 uint32_t i = 0;
252 for(i = 0; i < t; ++i) {
253 sq.push_back(polyn_gf2m(t + 1, g.get_sp_field()));
254 }
255 for(i = 0; i < d / 2; ++i) {
256 sq[i].set_degree(2 * i);
257 (*&sq[i]).set_coef(2 * i, 1);
258 }
259
260 for(; i < d; ++i) {
261 clear_mem(sq[i].m_coeff.data(), 2);
262 copy_mem(sq[i].m_coeff.data() + 2, sq[i - 1].m_coeff.data(), d);
263 sq[i].set_degree(sq[i - 1].get_degree() + 2);
264 polyn_gf2m::remainder(sq[i], g);
265 }
266 return sq;
267}
268
269/*Modulo p square of a certain polynomial g, sq[] contains the square
270Modulo g of the base canonical polynomials of degree < d, where d is
271the degree of G. The table sq[] will be calculated by polyn_gf2m_sqmod_init*/
272polyn_gf2m polyn_gf2m::sqmod(const std::vector<polyn_gf2m>& sq, int d) {
273 int i = 0;
274 const std::shared_ptr<GF2m_Field> sp_field = this->m_sp_field;
275
276 polyn_gf2m result(d - 1, sp_field);
277 // terms of low degree
278 for(i = 0; i < d / 2; ++i) {
279 (*&result).set_coef(i * 2, sp_field->gf_square((*this)[i]));
280 }
281
282 // terms of high degree
283 for(; i < d; ++i) {
284 gf2m lpi = (*this)[i];
285 if(lpi != 0) {
286 lpi = sp_field->gf_log(lpi);
287 const gf2m la = sp_field->gf_mul_rrr(lpi, lpi);
288 for(int j = 0; j < d; ++j) {
289 result[j] ^= sp_field->gf_mul_zrz(la, sq[i][j]);
290 }
291 }
292 }
293
294 // Update degre
295 result.set_degree(d - 1);
296 while((result.get_degree() >= 0) && (result[result.get_degree()] == 0)) {
297 result.set_degree(result.get_degree() - 1);
298 }
299 return result;
300}
301
302// destructive
303polyn_gf2m polyn_gf2m::gcd_aux(polyn_gf2m& p1, polyn_gf2m& p2) {
304 if(p2.get_degree() == -1) {
305 return p1;
306 } else {
307 polyn_gf2m::remainder(p1, p2);
308 return polyn_gf2m::gcd_aux(p2, p1);
309 }
310}
311
312polyn_gf2m polyn_gf2m::gcd(const polyn_gf2m& p1, const polyn_gf2m& p2) {
313 polyn_gf2m a(p1);
314 polyn_gf2m b(p2);
315 if(a.get_degree() < b.get_degree()) {
316 return polyn_gf2m(polyn_gf2m::gcd_aux(b, a));
317 } else {
318 return polyn_gf2m(polyn_gf2m::gcd_aux(a, b));
319 }
320}
321
322// Returns the degree of the smallest factor
325
326 const size_t ext_deg = g.m_sp_field->get_extension_degree();
327 const int d = g.get_degree();
328 const std::vector<polyn_gf2m> u = polyn_gf2m::sqmod_init(g);
329
330 polyn_gf2m p(d - 1, g.m_sp_field);
331
332 p.set_degree(1);
333 (*&p).set_coef(1, 1);
334 size_t result = static_cast<size_t>(d);
335 for(size_t i = 1; i <= (d / 2) * ext_deg; ++i) {
336 polyn_gf2m r = p.sqmod(u, d);
337 if((i % ext_deg) == 0) {
338 r[1] ^= 1;
339 r.get_degree(); // The degree may change
340 s = polyn_gf2m::gcd(g, r);
341
342 if(s.get_degree() > 0) {
343 result = i / ext_deg;
344 break;
345 }
346 r[1] ^= 1;
347 r.get_degree(); // The degree may change
348 }
349 // No need for the exchange s
350 s = p;
351 p = r;
352 r = s;
353 }
354
355 return result;
356}
357
358void polyn_gf2m::patchup_deg_secure(uint32_t trgt_deg, gf2m patch_elem) {
359 if(this->m_coeff.size() < trgt_deg) {
360 return;
361 }
362 for(uint32_t i = 0; i < this->m_coeff.size(); i++) {
363 this->m_coeff[i] |= patch_elem;
364 const uint32_t equal = (i == trgt_deg);
365 const uint32_t equal_mask = expand_mask_16bit(equal);
366 patch_elem &= ~equal_mask;
367 }
368 this->calc_degree_secure();
369}
370
371// We suppose m_deg(g) >= m_deg(p)
372// v is the problem
373std::pair<polyn_gf2m, polyn_gf2m> polyn_gf2m::eea_with_coefficients(const polyn_gf2m& p,
374 const polyn_gf2m& g,
375 int break_deg) {
376 const std::shared_ptr<GF2m_Field> m_sp_field = g.m_sp_field;
377 polyn_gf2m aux;
378
379 // initialisation of the local variables
380 // r0 <- g, r1 <- p, u0 <- 0, u1 <- 1
381 int dr = g.get_degree();
382
383 BOTAN_ASSERT(dr > 3, "Valid polynomial");
384
385 polyn_gf2m r0(dr, g.m_sp_field);
386 polyn_gf2m r1(dr - 1, g.m_sp_field);
387 polyn_gf2m u0(dr - 1, g.m_sp_field);
388 polyn_gf2m u1(dr - 1, g.m_sp_field);
389
390 r0 = g;
391 r1 = p;
392 u0.set_to_zero();
393 u1.set_to_zero();
394 (*&u1).set_coef(0, 1);
395 u1.set_degree(0);
396
397 // invariants:
398 // r1 = u1 * p + v1 * g
399 // r0 = u0 * p + v0 * g
400 // and m_deg(u1) = m_deg(g) - m_deg(r0)
401 // It stops when m_deg (r1) <t (m_deg (r0)> = t)
402 // And therefore m_deg (u1) = m_deg (g) - m_deg (r0) <m_deg (g) - break_deg
403 int du = 0;
404 dr = r1.get_degree();
405 int delta = r0.get_degree() - dr;
406
407 int i = 0;
408 int j = 0;
409 while(dr >= break_deg) {
410 for(j = delta; j >= 0; --j) {
411 const gf2m a = m_sp_field->gf_div(r0[dr + j], r1[dr]);
412 if(a != 0) {
413 const gf2m la = m_sp_field->gf_log(a);
414 // u0(z) <- u0(z) + a * u1(z) * z^j
415 for(i = 0; i <= du; ++i) {
416 u0[i + j] ^= m_sp_field->gf_mul_zrz(la, u1[i]);
417 }
418 // r0(z) <- r0(z) + a * r1(z) * z^j
419 for(i = 0; i <= dr; ++i) {
420 r0[i + j] ^= m_sp_field->gf_mul_zrz(la, r1[i]);
421 }
422 }
423 } // end loop over j
424
425 if(break_deg != 1) /* key eq. solving */
426 {
427 /* [ssms_icisc09] Countermeasure
428 * d_break from paper equals break_deg - 1
429 * */
430
431 volatile gf2m fake_elem = 0x01;
432 volatile gf2m cond1 = 0;
433 volatile gf2m cond2 = 0;
434 const int trgt_deg = r1.get_degree() - 1;
437 if(!(g.get_degree() % 2)) {
438 /* t even */
439 cond1 = r0.get_degree() < break_deg - 1;
440 } else {
441 /* t odd */
442 cond1 = r0.get_degree() < break_deg;
443 cond2 = u0.get_degree() < break_deg - 1;
444 cond1 = cond1 & cond2;
445 }
446 /* expand cond1 to a full mask */
447 const gf2m mask = generate_gf2m_mask(cond1);
448 fake_elem = fake_elem & mask;
449 r0.patchup_deg_secure(trgt_deg, fake_elem);
450 }
451 if(break_deg == 1) /* syndrome inversion */
452 {
453 volatile gf2m fake_elem = 0x00;
454 volatile uint32_t trgt_deg = 0;
457 /**
458 * countermeasure against the low weight attacks for w=4, w=6 and w=8.
459 * Higher values are not covered since for w=8 we already have a
460 * probability for a positive of 1/n^3 from random ciphertexts with the
461 * given weight. For w = 10 it would be 1/n^4 and so on. Thus attacks
462 * based on such high values of w are considered impractical.
463 *
464 * The outer test for the degree of u ( Omega in the paper ) needs not to
465 * be disguised. Each of the three is performed at most once per EEA
466 * (syndrome inversion) execution, the attacker knows this already when
467 * preparing the ciphertext with the given weight. Inside these three
468 * cases however, we must use timing neutral (branch free) operations to
469 * implement the condition detection and the counteractions.
470 *
471 */
472 if(u0.get_degree() == 4) {
473 uint32_t mask = 0;
474 /**
475 * Condition that the EEA would break now
476 */
477 int cond_r = r0.get_degree() == 0;
478 /**
479 * Now come the conditions for all odd coefficients of this sigma
480 * candidate. If they are all fulfilled, then we know that we have a low
481 * weight error vector, since the key-equation solving EEA is skipped if
482 * the degree of tau^2 is low (=m_deg(u0)) and all its odd coefficients are
483 * zero (they would cause "full-length" contributions from the square
484 * root computation).
485 */
486 // Condition for the coefficient to Y to be cancelled out by the
487 // addition of Y before the square root computation:
488 const int cond_u1 = m_sp_field->gf_mul(u0.m_coeff[1], m_sp_field->gf_inv(r0.m_coeff[0])) == 1;
489
490 // Condition sigma_3 = 0:
491 const int cond_u3 = u0.m_coeff[3] == 0;
492 // combine the conditions:
493 cond_r &= (cond_u1 & cond_u3);
494 // mask generation:
495 mask = expand_mask_16bit(cond_r);
496 trgt_deg = 2 & mask;
497 fake_elem = 1 & mask;
498 } else if(u0.get_degree() == 6) {
499 uint32_t mask = 0;
500 int cond_r = r0.get_degree() == 0;
501 const int cond_u1 = m_sp_field->gf_mul(u0.m_coeff[1], m_sp_field->gf_inv(r0.m_coeff[0])) == 1;
502 const int cond_u3 = u0.m_coeff[3] == 0;
503
504 const int cond_u5 = u0.m_coeff[5] == 0;
505
506 cond_r &= (cond_u1 & cond_u3 & cond_u5);
507 mask = expand_mask_16bit(cond_r);
508 trgt_deg = 4 & mask;
509 fake_elem = 1 & mask;
510 } else if(u0.get_degree() == 8) {
511 uint32_t mask = 0;
512 int cond_r = r0.get_degree() == 0;
513 const int cond_u1 = m_sp_field->gf_mul(u0[1], m_sp_field->gf_inv(r0[0])) == 1;
514 const int cond_u3 = u0.m_coeff[3] == 0;
515
516 const int cond_u5 = u0.m_coeff[5] == 0;
517
518 const int cond_u7 = u0.m_coeff[7] == 0;
519
520 cond_r &= (cond_u1 & cond_u3 & cond_u5 & cond_u7);
521 mask = expand_mask_16bit(cond_r);
522 trgt_deg = 6 & mask;
523 fake_elem = 1 & mask;
524 }
525 r0.patchup_deg_secure(trgt_deg, fake_elem);
526 }
527 // exchange
528 aux = r0;
529 r0 = r1;
530 r1 = aux;
531 aux = u0;
532 u0 = u1;
533 u1 = aux;
534
535 du = du + delta;
536 delta = 1;
537 while(r1[dr - delta] == 0) {
538 delta++;
539 }
540
541 dr -= delta;
542 } /* end while loop (dr >= break_deg) */
543
544 u1.set_degree(du);
545 r1.set_degree(dr);
546 //return u1 and r1;
547 return std::make_pair(u1, r1); // coefficients u,v
548}
549
550polyn_gf2m::polyn_gf2m(size_t t, RandomNumberGenerator& rng, const std::shared_ptr<GF2m_Field>& sp_field) :
551 m_deg(static_cast<int>(t)), m_coeff(t + 1), m_sp_field(sp_field) {
552 this->set_coef(t, 1);
553 for(;;) {
554 for(size_t i = 0; i < t; ++i) {
555 this->set_coef(i, random_code_element(sp_field->get_cardinality(), rng));
556 }
557
558 const size_t degree = polyn_gf2m::degppf(*this);
559
560 if(degree >= t) {
561 break;
562 }
563 }
564}
565
566void polyn_gf2m::poly_shiftmod(const polyn_gf2m& g) {
567 if(g.get_degree() <= 1) {
568 throw Invalid_Argument("shiftmod cannot be called on polynomials of degree 1 or less");
569 }
570 const std::shared_ptr<GF2m_Field> field = g.m_sp_field;
571
572 const int t = g.get_degree();
573 const gf2m a = field->gf_div(this->m_coeff[t - 1], g.m_coeff[t]);
574 for(int i = t - 1; i > 0; --i) {
575 this->m_coeff[i] = this->m_coeff[i - 1] ^ this->m_sp_field->gf_mul(a, g.m_coeff[i]);
576 }
577 this->m_coeff[0] = field->gf_mul(a, g.m_coeff[0]);
578}
579
580std::vector<polyn_gf2m> polyn_gf2m::sqrt_mod_init(const polyn_gf2m& g) {
581 uint32_t i = 0;
582 uint32_t t = 0;
583 uint32_t nb_polyn_sqrt_mat = 0;
584 const std::shared_ptr<GF2m_Field> m_sp_field = g.m_sp_field;
585 std::vector<polyn_gf2m> result;
586 t = g.get_degree();
587 nb_polyn_sqrt_mat = t / 2;
588
589 const std::vector<polyn_gf2m> sq_aux = polyn_gf2m::sqmod_init(g);
590
591 polyn_gf2m p(t - 1, g.get_sp_field());
592 p.set_degree(1);
593
594 (*&p).set_coef(1, 1);
595 // q(z) = 0, p(z) = z
596 for(i = 0; i < t * m_sp_field->get_extension_degree() - 1; ++i) {
597 // q(z) <- p(z)^2 mod g(z)
598 polyn_gf2m q = p.sqmod(sq_aux, t);
599 // q(z) <-> p(z)
600 const polyn_gf2m aux = q;
601 q = p;
602 p = aux;
603 }
604 // p(z) = z^(2^(tm-1)) mod g(z) = sqrt(z) mod g(z)
605
606 for(i = 0; i < nb_polyn_sqrt_mat; ++i) {
607 result.push_back(polyn_gf2m(t - 1, g.get_sp_field()));
608 }
609
610 result[0] = p;
611 result[0].get_degree();
612 for(i = 1; i < nb_polyn_sqrt_mat; i++) {
613 result[i] = result[i - 1];
614 result[i].poly_shiftmod(g);
615 result[i].get_degree();
616 }
617
618 return result;
619}
620
621std::vector<polyn_gf2m> syndrome_init(const polyn_gf2m& generator, const std::vector<gf2m>& support, int n) {
622 int i = 0;
623 int j = 0;
624 int t = 0;
625 gf2m a = 0;
626
627 const std::shared_ptr<GF2m_Field> m_sp_field = generator.get_sp_field();
628
629 std::vector<polyn_gf2m> result;
630 t = generator.get_degree();
631
632 //g(z)=g_t+g_(t-1).z^(t-1)+......+g_1.z+g_0
633 //f(z)=f_(t-1).z^(t-1)+......+f_1.z+f_0
634
635 for(j = 0; j < n; j++) {
636 result.push_back(polyn_gf2m(t - 1, m_sp_field));
637
638 (*&result[j]).set_coef(t - 1, 1);
639 for(i = t - 2; i >= 0; i--) {
640 (*&result[j]).set_coef(i, (generator)[i + 1] ^ m_sp_field->gf_mul(lex_to_gray(support[j]), result[j][i + 1]));
641 }
642 a = ((generator)[0] ^ m_sp_field->gf_mul(lex_to_gray(support[j]), result[j][0]));
643 for(i = 0; i < t; i++) {
644 (*&result[j]).set_coef(i, m_sp_field->gf_div(result[j][i], a));
645 }
646 }
647 return result;
648}
649
650polyn_gf2m::polyn_gf2m(const secure_vector<uint8_t>& encoded, const std::shared_ptr<GF2m_Field>& sp_field) :
651 m_sp_field(sp_field) {
652 if(!sp_field) {
653 throw Decoding_Error("missing field for polynomial decoding");
654 }
655
656 if(encoded.size() % 2) {
657 throw Decoding_Error("encoded polynomial has odd length");
658 }
659 const size_t field_cardinality = static_cast<size_t>(1) << sp_field->get_extension_degree();
660 for(uint32_t i = 0; i < encoded.size(); i += 2) {
661 const gf2m el = (encoded[i] << 8) | encoded[i + 1];
662 if(el >= field_cardinality) {
663 throw Decoding_Error("encoded polynomial coefficient is out of range");
664 }
665 m_coeff.push_back(el);
666 }
667 get_degree();
668}
669
672
673 if(m_deg < 1) {
674 result.push_back(0);
675 result.push_back(0);
676 return result;
677 }
678
679 const uint32_t len = m_deg + 1;
680 for(unsigned i = 0; i < len; i++) {
681 // "big endian" encoding of the GF(2^m) elements
682 result.push_back(get_byte<0>(m_coeff[i]));
683 result.push_back(get_byte<1>(m_coeff[i]));
684 }
685 return result;
686}
687
688void polyn_gf2m::swap(polyn_gf2m& other) noexcept {
689 std::swap(this->m_deg, other.m_deg);
690 std::swap(this->m_sp_field, other.m_sp_field);
691 std::swap(this->m_coeff, other.m_coeff);
692}
693
694bool polyn_gf2m::operator==(const polyn_gf2m& other) const {
695 return m_deg == other.m_deg && m_coeff == other.m_coeff;
696}
697
698// NOLINTEND(*-implicit-bool-conversion)
699
700} // namespace Botan
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:62
void randomize(std::span< uint8_t > output)
Definition rng.h:86
secure_vector< uint8_t > encode() const
int get_degree() const
std::shared_ptr< GF2m_Field > get_sp_field() const
Definition polyn_gf2m.h:79
static std::pair< polyn_gf2m, polyn_gf2m > eea_with_coefficients(const polyn_gf2m &p, const polyn_gf2m &g, int break_deg)
void set_coef(size_t i, gf2m v)
Definition polyn_gf2m.h:89
polyn_gf2m(const std::shared_ptr< GF2m_Field > &sp_field)
void swap(polyn_gf2m &other) noexcept
gf2m get_lead_coef() const
Definition polyn_gf2m.h:85
void patchup_deg_secure(uint32_t trgt_deg, gf2m patch_elem)
static std::vector< polyn_gf2m > sqmod_init(const polyn_gf2m &g)
static std::vector< polyn_gf2m > sqrt_mod_init(const polyn_gf2m &g)
int calc_degree_secure() const
bool operator==(const polyn_gf2m &other) const
polyn_gf2m sqmod(const std::vector< polyn_gf2m > &sq, int d)
gf2m eval(gf2m a)
static size_t degppf(const polyn_gf2m &g)
constexpr uint8_t get_byte(T input)
Definition loadstor.h:79
gf2m lex_to_gray(gf2m lex)
uint16_t expand_mask_16bit(T tst)
gf2m random_code_element(uint16_t code_length, RandomNumberGenerator &rng)
std::vector< polyn_gf2m > syndrome_init(const polyn_gf2m &generator, const std::vector< gf2m > &support, int n)
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:144
gf2m random_gf2m(RandomNumberGenerator &rng)
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:128
gf2m decode_gf2m(const uint8_t *mem)
constexpr void clear_mem(T *ptr, size_t n)
Definition mem_ops.h:118
uint16_t gf2m
constexpr uint16_t make_uint16(uint8_t i0, uint8_t i1)
Definition loadstor.h:92