Coverage Report

Created: 2019-12-03 15:21

/src/botan/src/lib/pubkey/mce/gf2m_rootfind_dcmp.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * (C) 2014 cryptosource GmbH
3
 * (C) 2014 Falko Strenzke fstrenzke@cryptosource.de
4
 *
5
 * Botan is released under the Simplified BSD License (see license.txt)
6
 *
7
 */
8
9
#include <botan/polyn_gf2m.h>
10
#include <botan/internal/bit_ops.h>
11
#include <botan/internal/code_based_util.h>
12
#include <botan/exceptn.h>
13
14
namespace Botan {
15
16
namespace {
17
18
uint32_t patch_root_array(gf2m* res_root_arr,
19
                        uint32_t res_root_arr_len,
20
                        uint32_t root_pos)
21
0
   {
22
0
   volatile gf2m patch_elem = 0x01;
23
0
   volatile gf2m cond_mask = (root_pos == res_root_arr_len);
24
0
   cond_mask = expand_mask_16bit(cond_mask);
25
0
   cond_mask = ~cond_mask; /* now cond = 1 if not enough roots */
26
0
   patch_elem &= cond_mask;
27
0
   for(size_t i = 0; i < res_root_arr_len; i++)
28
0
      {
29
0
      gf2m masked_patch_elem = (patch_elem++) & cond_mask;
30
0
      res_root_arr[i] ^= masked_patch_elem++;
31
0
      }
32
0
   return res_root_arr_len;
33
0
   }
34
35
class gf2m_decomp_rootfind_state
36
   {
37
   public:
38
      gf2m_decomp_rootfind_state(const polyn_gf2m & p_polyn, uint32_t code_length);
39
40
      void calc_LiK(const polyn_gf2m & sigma);
41
      gf2m calc_Fxj_j_neq_0( const polyn_gf2m & sigma, gf2m j_gray);
42
      void calc_next_Aij();
43
      void calc_Ai_zero(const polyn_gf2m & sigma);
44
      secure_vector<gf2m> find_roots(const polyn_gf2m & sigma);
45
0
      uint32_t get_code_length() const { return code_length; }
46
      uint32_t code_length;
47
      secure_vector<gf2m> m_Lik; // size is outer_summands * m
48
      secure_vector<gf2m> m_Aij; // ...
49
      uint32_t m_outer_summands;
50
      gf2m m_j;
51
      gf2m m_j_gray;
52
      gf2m m_sigma_3_l;
53
      gf2m m_sigma_3_neq_0_mask;
54
   };
55
56
/*
57
* !! Attention: assumes gf2m is 16bit !!
58
*/
59
#if 0
60
gf2m brootf_decomp_gray_to_lex(gf2m gray)
61
   {
62
   static_assert(sizeof(gf2m) == 2, "Expected size");
63
   gf2m result = gray ^ (gray>>8);
64
   result ^= (result >> 4);
65
   result ^= (result >> 2);
66
   result ^= (result >> 1);
67
   return result;
68
   }
69
#endif
70
71
/**
72
* calculates ceil((t-4)/5) = outer_summands - 1
73
*/
74
uint32_t brootf_decomp_calc_sum_limit(uint32_t t)
75
0
   {
76
0
   uint32_t result;
77
0
   if(t < 4)
78
0
      {
79
0
      return 0;
80
0
      }
81
0
   result = t - 4;
82
0
   result += 4;
83
0
   result /= 5;
84
0
   return result;
85
0
   }
86
87
gf2m_decomp_rootfind_state::gf2m_decomp_rootfind_state(const polyn_gf2m & polyn, uint32_t the_code_length) :
88
   code_length(the_code_length), m_j(0), m_j_gray(0)
89
0
   {
90
0
   gf2m coeff_3;
91
0
   gf2m coeff_head;
92
0
   std::shared_ptr<GF2m_Field> sp_field = polyn.get_sp_field();
93
0
   int deg_sigma = polyn.get_degree();
94
0
   if(deg_sigma <= 3)
95
0
      {
96
0
      throw Internal_Error("Unexpected degree in gf2m_decomp_rootfind_state");
97
0
      }
98
0
99
0
   coeff_3 = polyn.get_coef( 3);
100
0
   coeff_head = polyn.get_coef( deg_sigma); /* dummy value for SCA CM */
101
0
   if(coeff_3 != 0)
102
0
      {
103
0
      this->m_sigma_3_l = sp_field->gf_l_from_n(coeff_3);
104
0
      this->m_sigma_3_neq_0_mask = 0xFFFF;
105
0
      }
106
0
   else
107
0
      {
108
0
      // dummy value needed for timing countermeasure
109
0
      this->m_sigma_3_l = sp_field->gf_l_from_n(coeff_head);
110
0
      this->m_sigma_3_neq_0_mask = 0 ;
111
0
      }
112
0
113
0
   this->m_outer_summands =  1 + brootf_decomp_calc_sum_limit(deg_sigma);
114
0
   this->m_Lik.resize(this->m_outer_summands * sp_field->get_extension_degree());
115
0
   this->m_Aij.resize(this->m_outer_summands);
116
0
   }
117
118
void gf2m_decomp_rootfind_state::calc_Ai_zero(const polyn_gf2m & sigma)
119
0
   {
120
0
   uint32_t i;
121
0
   /*
122
0
   * this function assumes this the first gray code element is zero
123
0
   */
124
0
   for(i = 0; i < this->m_outer_summands; i++)
125
0
      {
126
0
      this->m_Aij[i] = sigma.get_coef(5*i);
127
0
      }
128
0
   this->m_j = 0;
129
0
   this->m_j_gray = 0;
130
0
   }
131
132
void gf2m_decomp_rootfind_state::calc_next_Aij()
133
0
   {
134
0
   /*
135
0
   * upon function entry, we have in the state j, Aij.
136
0
   * first thing, we declare Aij Aij_minusone and increase j.
137
0
   * Case j=0 upon function entry also included, then Aij contains A_{i,j=0}.
138
0
   */
139
0
   uint32_t i;
140
0
   gf2m diff, new_j_gray;
141
0
   uint32_t Lik_pos_base;
142
0
143
0
   this->m_j++;
144
0
145
0
   new_j_gray =  lex_to_gray(this->m_j);
146
0
147
0
   if(this->m_j & 1)  /* half of the times */
148
0
      {
149
0
      Lik_pos_base = 0;
150
0
      }
151
0
   else if(this->m_j & 2) /* one quarter of the times */
152
0
      {
153
0
      Lik_pos_base = this->m_outer_summands;
154
0
      }
155
0
   else if( this->m_j & 4) /* one eighth of the times */
156
0
      {
157
0
      Lik_pos_base = this->m_outer_summands * 2;
158
0
      }
159
0
   else if( this->m_j & 8) /* one sixteenth of the times */
160
0
      {
161
0
      Lik_pos_base = this->m_outer_summands * 3;
162
0
      }
163
0
   else if( this->m_j & 16) /* ... */
164
0
      {
165
0
      Lik_pos_base = this->m_outer_summands * 4;
166
0
      }
167
0
   else
168
0
      {
169
0
      gf2m delta_offs = 5;
170
0
      diff = this->m_j_gray ^ new_j_gray;
171
0
      while(((static_cast<gf2m>(1) << delta_offs) & diff) == 0)
172
0
         {
173
0
         delta_offs++;
174
0
175
0
         }
176
0
      Lik_pos_base = delta_offs * this->m_outer_summands;
177
0
      }
178
0
   this->m_j_gray = new_j_gray;
179
0
180
0
   i = 0;
181
0
   for(; i < this->m_outer_summands; i++)
182
0
      {
183
0
      this->m_Aij[i] ^= this->m_Lik[Lik_pos_base + i];
184
0
      }
185
0
186
0
   }
187
188
void gf2m_decomp_rootfind_state::calc_LiK(const polyn_gf2m & sigma)
189
0
   {
190
0
   std::shared_ptr<GF2m_Field> sp_field = sigma.get_sp_field();
191
0
   uint32_t i, k, d;
192
0
   d = sigma.get_degree();
193
0
   for(k = 0; k < sp_field->get_extension_degree(); k++)
194
0
      {
195
0
      uint32_t Lik_pos_base = k * this->m_outer_summands;
196
0
      gf2m alpha_l_k_tt2_ttj[4];
197
0
      alpha_l_k_tt2_ttj[0] = sp_field->gf_l_from_n(static_cast<gf2m>(1) << k);
198
0
      alpha_l_k_tt2_ttj[1] = sp_field->gf_mul_rrr(alpha_l_k_tt2_ttj[0], alpha_l_k_tt2_ttj[0]);
199
0
      alpha_l_k_tt2_ttj[2] = sp_field->gf_mul_rrr(alpha_l_k_tt2_ttj[1],alpha_l_k_tt2_ttj[1] );
200
0
201
0
      alpha_l_k_tt2_ttj[3] = sp_field->gf_mul_rrr(alpha_l_k_tt2_ttj[2], alpha_l_k_tt2_ttj[2]);
202
0
      for(i = 0; i < this->m_outer_summands; i++)
203
0
         {
204
0
         uint32_t j;
205
0
         uint32_t five_i = 5*i;
206
0
         uint32_t Lik_pos = Lik_pos_base + i;
207
0
         this->m_Lik[Lik_pos] = 0;
208
0
         for(j = 0; j <= 3; j++)
209
0
            {
210
0
            gf2m f, x;
211
0
            uint32_t f_ind = five_i + (static_cast<uint32_t>(1) << j);
212
0
            if(f_ind > d)
213
0
               {
214
0
               break;
215
0
               }
216
0
            f = sigma.get_coef( f_ind);
217
0
218
0
            x = sp_field->gf_mul_zrz(alpha_l_k_tt2_ttj[j], f);
219
0
            this->m_Lik[Lik_pos] ^= x;
220
0
            }
221
0
         }
222
0
      }
223
0
   }
224
225
gf2m gf2m_decomp_rootfind_state::calc_Fxj_j_neq_0( const polyn_gf2m & sigma, gf2m j_gray)
226
0
   {
227
0
   //needs the A_{ij} to compute F(x)_j
228
0
   gf2m sum = 0;
229
0
   uint32_t i;
230
0
   std::shared_ptr<GF2m_Field> sp_field = sigma.get_sp_field();
231
0
   const gf2m jl_gray = sp_field->gf_l_from_n(j_gray);
232
0
   gf2m xl_j_tt_5 = sp_field->gf_square_rr(jl_gray);
233
0
   gf2m xl_gray_tt_3 = sp_field->gf_mul_rrr(xl_j_tt_5, jl_gray);
234
0
   xl_j_tt_5 = sp_field->gf_mul_rrr(xl_j_tt_5, xl_gray_tt_3);
235
0
236
0
237
0
   sum = sp_field->gf_mul_nrr(xl_gray_tt_3, this->m_sigma_3_l);
238
0
   sum &= this->m_sigma_3_neq_0_mask;
239
0
   /* here, we rely on compiler to be unable to optimize
240
0
   * for the state->sigma_3_neq_0_mask value
241
0
   */
242
0
   /* treat i = 0 special: */
243
0
   sum ^= this->m_Aij[0];
244
0
   /* treat i = 1 special also */
245
0
246
0
   if(this->m_outer_summands > 1)
247
0
      {
248
0
      gf2m x;
249
0
      x = sp_field->gf_mul_zrz(xl_j_tt_5, this->m_Aij[1]); /* x_j^{5i} A_i^j */
250
0
      sum ^= x;
251
0
      }
252
0
253
0
   gf2m xl_j_tt_5i = xl_j_tt_5;
254
0
255
0
   for(i = 2; i < this->m_outer_summands; i++)
256
0
      {
257
0
      gf2m x;
258
0
      xl_j_tt_5i = sp_field->gf_mul_rrr(xl_j_tt_5i, xl_j_tt_5);
259
0
      // now x_j_tt_5i lives up to its name
260
0
      x = sp_field->gf_mul_zrz(xl_j_tt_5i, this->m_Aij[i]); /* x_j^{5i} A_i^(j) */
261
0
      sum ^= x;
262
0
      }
263
0
   return sum;
264
0
   }
265
266
secure_vector<gf2m> gf2m_decomp_rootfind_state::find_roots(const polyn_gf2m & sigma)
267
0
   {
268
0
   const int sigma_degree = sigma.get_degree();
269
0
   BOTAN_ASSERT(sigma_degree > 0, "Valid sigma");
270
0
   secure_vector<gf2m> result(sigma_degree);
271
0
   uint32_t root_pos = 0;
272
0
273
0
   this->calc_Ai_zero(sigma);
274
0
   this->calc_LiK(sigma);
275
0
   do
276
0
      {
277
0
      gf2m eval_result;
278
0
      if(this->m_j_gray == 0)
279
0
         {
280
0
         eval_result = sigma.get_coef( 0);
281
0
         }
282
0
      else
283
0
         {
284
0
         eval_result = this->calc_Fxj_j_neq_0(sigma, this->m_j_gray);
285
0
         }
286
0
287
0
      if(eval_result == 0)
288
0
         {
289
0
290
0
         result[root_pos] = this->m_j_gray;
291
0
         root_pos++;
292
0
293
0
         }
294
0
      if(this->m_j + static_cast<uint32_t>(1) == this->get_code_length())
295
0
         {
296
0
         break;
297
0
         }
298
0
      this->calc_next_Aij();
299
0
      }while(1);
300
0
301
0
   // side channel / fault attack countermeasure:
302
0
   root_pos = patch_root_array(result.data(), result.size(), root_pos);
303
0
   result.resize(root_pos);
304
0
   return result;
305
0
   }
306
307
} // end anonymous namespace
308
309
secure_vector<gf2m> find_roots_gf2m_decomp(const polyn_gf2m & polyn, uint32_t code_length)
310
0
   {
311
0
   gf2m_decomp_rootfind_state state(polyn, code_length);
312
0
   return state.find_roots(polyn);
313
0
   }
314
315
} // end namespace Botan