Coverage Report

Created: 2019-09-11 14:12

/src/botan/src/lib/pubkey/mce/goppa_code.cpp
Line
Count
Source (jump to first uncovered line)
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
 *
8
 * Botan is released under the Simplified BSD License (see license.txt)
9
 *
10
 */
11
12
#include <botan/internal/mce_internal.h>
13
#include <botan/internal/code_based_util.h>
14
15
namespace Botan {
16
17
namespace {
18
19
void matrix_arr_mul(std::vector<uint32_t> matrix,
20
                    uint32_t numo_rows,
21
                    uint32_t words_per_row,
22
                    const uint8_t* input_vec,
23
                    uint32_t* output_vec, uint32_t output_vec_len)
24
0
   {
25
0
   for(size_t j = 0; j < numo_rows; j++)
26
0
      {
27
0
      if((input_vec[j / 8] >> (j % 8)) & 1)
28
0
         {
29
0
         for(size_t i = 0; i < output_vec_len; i ++)
30
0
            {
31
0
            output_vec[i] ^= matrix[ j * (words_per_row) + i];
32
0
            }
33
0
         }
34
0
      }
35
0
   }
36
37
/**
38
* returns the error vector to the syndrome
39
*/
40
secure_vector<gf2m> goppa_decode(const polyn_gf2m & syndrom_polyn,
41
                                 const polyn_gf2m & g,
42
                                 const std::vector<polyn_gf2m> & sqrtmod,
43
                                 const std::vector<gf2m> & Linv)
44
0
   {
45
0
   gf2m a;
46
0
   uint32_t code_length = Linv.size();
47
0
   uint32_t t = g.get_degree();
48
0
49
0
   std::shared_ptr<GF2m_Field> sp_field = g.get_sp_field();
50
0
51
0
   std::pair<polyn_gf2m, polyn_gf2m> h_aux = polyn_gf2m::eea_with_coefficients( syndrom_polyn, g, 1);
52
0
   polyn_gf2m & h = h_aux.first;
53
0
   polyn_gf2m & aux = h_aux.second;
54
0
   a = sp_field->gf_inv(aux.get_coef(0));
55
0
   gf2m log_a = sp_field->gf_log(a);
56
0
   for(int i = 0; i <= h.get_degree(); ++i)
57
0
      {
58
0
      h.set_coef(i,sp_field->gf_mul_zrz(log_a,h.get_coef(i)));
59
0
      }
60
0
61
0
   //  compute h(z) += z
62
0
   h.add_to_coef( 1, 1);
63
0
   // compute S square root of h (using sqrtmod)
64
0
   polyn_gf2m S(t - 1, g.get_sp_field());
65
0
66
0
   for(uint32_t i=0;i<t;i++)
67
0
      {
68
0
      a = sp_field->gf_sqrt(h.get_coef(i));
69
0
70
0
      if(i & 1)
71
0
         {
72
0
         for(uint32_t j=0;j<t;j++)
73
0
            {
74
0
            S.add_to_coef( j, sp_field->gf_mul(a, sqrtmod[i/2].get_coef(j)));
75
0
            }
76
0
         }
77
0
      else
78
0
         {
79
0
         S.add_to_coef( i/2, a);
80
0
         }
81
0
      } /* end for loop (i) */
82
0
83
0
84
0
   S.get_degree();
85
0
86
0
   std::pair<polyn_gf2m, polyn_gf2m> v_u = polyn_gf2m::eea_with_coefficients(S, g, t/2+1);
87
0
   polyn_gf2m & u = v_u.second;
88
0
   polyn_gf2m & v = v_u.first;
89
0
90
0
   // sigma = u^2+z*v^2
91
0
   polyn_gf2m sigma ( t , g.get_sp_field());
92
0
93
0
   const int u_deg = u.get_degree();
94
0
   BOTAN_ASSERT(u_deg >= 0, "Valid degree");
95
0
   for(int i = 0; i <= u_deg; ++i)
96
0
      {
97
0
      sigma.set_coef(2*i, sp_field->gf_square(u.get_coef(i)));
98
0
      }
99
0
100
0
   const int v_deg = v.get_degree();
101
0
   BOTAN_ASSERT(v_deg >= 0, "Valid degree");
102
0
   for(int i = 0; i <= v_deg; ++i)
103
0
      {
104
0
      sigma.set_coef(2*i+1, sp_field->gf_square(v.get_coef(i)));
105
0
      }
106
0
107
0
   secure_vector<gf2m> res = find_roots_gf2m_decomp(sigma, code_length);
108
0
   size_t d = res.size();
109
0
110
0
   secure_vector<gf2m> result(d);
111
0
   for(uint32_t i = 0; i < d; ++i)
112
0
      {
113
0
      gf2m current = res[i];
114
0
115
0
      gf2m tmp;
116
0
      tmp = gray_to_lex(current);
117
0
      /// XXX double assignment, possible bug?
118
0
      if(tmp >= code_length) /* invalid root */
119
0
         {
120
0
         result[i] = static_cast<gf2m>(i);
121
0
         }
122
0
      result[i] = Linv[tmp];
123
0
      }
124
0
125
0
   return result;
126
0
   }
127
}
128
129
void mceliece_decrypt(secure_vector<uint8_t>& plaintext_out,
130
                      secure_vector<uint8_t>& error_mask_out,
131
                      const secure_vector<uint8_t>& ciphertext,
132
                      const McEliece_PrivateKey& key)
133
0
   {
134
0
   mceliece_decrypt(plaintext_out, error_mask_out, ciphertext.data(), ciphertext.size(), key);
135
0
   }
136
137
void mceliece_decrypt(
138
   secure_vector<uint8_t>& plaintext,
139
   secure_vector<uint8_t> & error_mask,
140
   const uint8_t ciphertext[],
141
   size_t ciphertext_len,
142
   const McEliece_PrivateKey & key)
143
0
   {
144
0
   secure_vector<gf2m> error_pos;
145
0
   plaintext = mceliece_decrypt(error_pos, ciphertext, ciphertext_len, key);
146
0
147
0
   const size_t code_length = key.get_code_length();
148
0
   secure_vector<uint8_t> result((code_length+7)/8);
149
0
   for(auto&& pos : error_pos)
150
0
      {
151
0
      if(pos > code_length)
152
0
         {
153
0
         throw Invalid_Argument("error position larger than code size");
154
0
         }
155
0
      result[pos / 8] |= (1 << (pos % 8));
156
0
      }
157
0
158
0
   error_mask = result;
159
0
   }
160
161
/**
162
* @p p_err_pos_len must point to the available length of @p error_pos on input, the
163
* function will set it to the actual number of errors returned in the @p error_pos
164
* array */
165
secure_vector<uint8_t> mceliece_decrypt(
166
   secure_vector<gf2m> & error_pos,
167
   const uint8_t *ciphertext, uint32_t ciphertext_len,
168
   const McEliece_PrivateKey & key)
169
0
   {
170
0
171
0
   uint32_t dimension = key.get_dimension();
172
0
   uint32_t codimension = key.get_codimension();
173
0
   uint32_t t = key.get_goppa_polyn().get_degree();
174
0
   polyn_gf2m syndrome_polyn(key.get_goppa_polyn().get_sp_field()); // init as zero polyn
175
0
   const unsigned unused_pt_bits = dimension % 8;
176
0
   const uint8_t unused_pt_bits_mask = (1 << unused_pt_bits) - 1;
177
0
178
0
   if(ciphertext_len != (key.get_code_length()+7)/8)
179
0
      {
180
0
      throw Invalid_Argument("wrong size of McEliece ciphertext");
181
0
      }
182
0
   uint32_t cleartext_len = (key.get_message_word_bit_length()+7)/8;
183
0
184
0
   if(cleartext_len != bit_size_to_byte_size(dimension))
185
0
      {
186
0
      throw Invalid_Argument("mce-decryption: wrong length of cleartext buffer");
187
0
      }
188
0
189
0
   secure_vector<uint32_t> syndrome_vec(bit_size_to_32bit_size(codimension));
190
0
   matrix_arr_mul(key.get_H_coeffs(),
191
0
                  key.get_code_length(),
192
0
                  bit_size_to_32bit_size(codimension),
193
0
                  ciphertext,
194
0
                  syndrome_vec.data(), syndrome_vec.size());
195
0
196
0
   secure_vector<uint8_t> syndrome_byte_vec(bit_size_to_byte_size(codimension));
197
0
   uint32_t syndrome_byte_vec_size = syndrome_byte_vec.size();
198
0
   for(uint32_t i = 0; i < syndrome_byte_vec_size; i++)
199
0
      {
200
0
      syndrome_byte_vec[i] = static_cast<uint8_t>(syndrome_vec[i/4] >> (8* (i % 4)));
201
0
      }
202
0
203
0
   syndrome_polyn = polyn_gf2m(t-1, syndrome_byte_vec.data(), bit_size_to_byte_size(codimension), key.get_goppa_polyn().get_sp_field());
204
0
205
0
   syndrome_polyn.get_degree();
206
0
   error_pos = goppa_decode(syndrome_polyn, key.get_goppa_polyn(), key.get_sqrtmod(), key.get_Linv());
207
0
208
0
   uint32_t nb_err = error_pos.size();
209
0
210
0
   secure_vector<uint8_t> cleartext(cleartext_len);
211
0
   copy_mem(cleartext.data(), ciphertext, cleartext_len);
212
0
213
0
   for(uint32_t i = 0; i < nb_err; i++)
214
0
      {
215
0
      gf2m current = error_pos[i];
216
0
217
0
      if(current >= cleartext_len * 8)
218
0
         {
219
0
         // an invalid position, this shouldn't happen
220
0
         continue;
221
0
         }
222
0
      cleartext[current / 8] ^= (1 << (current % 8));
223
0
      }
224
0
225
0
   if(unused_pt_bits)
226
0
      {
227
0
      cleartext[cleartext_len - 1] &= unused_pt_bits_mask;
228
0
      }
229
0
230
0
   return cleartext;
231
0
   }
232
233
}