• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 27806188297

18 Jun 2026 04:12PM UTC coverage: 89.37% (-0.03%) from 89.397%
27806188297

push

github

web-flow
Merge pull request #5677 from randombit/jack/oid-names

Add OID::registered_name

111637 of 124915 relevant lines covered (89.37%)

10895907.86 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.88
/src/lib/pubkey/mce/goppa_code.cpp
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

14
#include <botan/mem_ops.h>
15
#include <botan/internal/code_based_util.h>
16

17
namespace Botan {
18

19
namespace {
20

21
void matrix_arr_mul(const std::vector<uint32_t>& matrix,
212✔
22
                    size_t numo_rows,
23
                    size_t words_per_row,
24
                    const uint8_t input_vec[],
25
                    uint32_t output_vec[],
26
                    size_t output_vec_len) {
27
   for(size_t j = 0; j < numo_rows; j++) {
728,148✔
28
      if(((input_vec[j / 8] >> (j % 8)) & 1) != 0) {
727,936✔
29
         for(size_t i = 0; i < output_vec_len; i++) {
11,851,803✔
30
            output_vec[i] ^= matrix[j * (words_per_row) + i];
11,488,251✔
31
         }
32
      }
33
   }
34
}
212✔
35

36
/**
37
* returns the error vector to the syndrome
38
*/
39
secure_vector<gf2m> goppa_decode(const polyn_gf2m& syndrome_polyn,
212✔
40
                                 const polyn_gf2m& g,
41
                                 const std::vector<polyn_gf2m>& sqrtmod,
42
                                 const std::vector<gf2m>& Linv) {
43
   const size_t code_length = Linv.size();
212✔
44
   const uint32_t t = g.get_degree();
212✔
45

46
   const std::shared_ptr<GF2m_Field> sp_field = g.get_sp_field();
212✔
47

48
   std::pair<polyn_gf2m, polyn_gf2m> h_aux = polyn_gf2m::eea_with_coefficients(syndrome_polyn, g, 1);
212✔
49
   polyn_gf2m& h = h_aux.first;
212✔
50
   const polyn_gf2m& aux = h_aux.second;
212✔
51
   gf2m a = sp_field->gf_inv(aux.get_coef(0));
212✔
52
   const gf2m log_a = sp_field->gf_log(a);
212✔
53
   for(int i = 0; i <= h.get_degree(); ++i) {
14,056✔
54
      h.set_coef(i, sp_field->gf_mul_zrz(log_a, h.get_coef(i)));
27,684✔
55
   }
56

57
   //  compute h(z) += z
58
   h.add_to_coef(1, 1);
212✔
59
   // compute S square root of h (using sqrtmod)
60
   polyn_gf2m S(t - 1, g.get_sp_field());
212✔
61

62
   for(uint32_t i = 0; i < t; i++) {
14,056✔
63
      a = sp_field->gf_sqrt(h.get_coef(i));
13,844✔
64

65
      if((i & 1) != 0) {
13,844✔
66
         for(uint32_t j = 0; j < t; j++) {
540,416✔
67
            S.add_to_coef(j, sp_field->gf_mul(a, sqrtmod[i / 2].get_coef(j)));
1,067,143✔
68
         }
69
      } else {
70
         S.add_to_coef(i / 2, a);
7,028✔
71
      }
72
   } /* end for loop (i) */
73

74
   S.get_degree();
212✔
75

76
   const std::pair<polyn_gf2m, polyn_gf2m> v_u = polyn_gf2m::eea_with_coefficients(S, g, t / 2 + 1);
212✔
77
   const polyn_gf2m& u = v_u.second;
212✔
78
   const polyn_gf2m& v = v_u.first;
212✔
79

80
   // sigma = u^2+z*v^2
81
   polyn_gf2m sigma(t, g.get_sp_field());
212✔
82

83
   const int u_deg = u.get_degree();
212✔
84
   BOTAN_ASSERT(u_deg >= 0, "Valid degree");
212✔
85
   for(int i = 0; i <= u_deg; ++i) {
7,240✔
86
      sigma.set_coef(2 * i, sp_field->gf_square(u.get_coef(i)));
7,028✔
87
   }
88

89
   const int v_deg = v.get_degree();
212✔
90
   BOTAN_ASSERT(v_deg >= 0, "Valid degree");
212✔
91
   for(int i = 0; i <= v_deg; ++i) {
7,240✔
92
      sigma.set_coef(2 * i + 1, sp_field->gf_square(v.get_coef(i)));
7,028✔
93
   }
94

95
   secure_vector<gf2m> res = find_roots_gf2m_decomp(sigma, code_length);
212✔
96
   const size_t d = res.size();
212✔
97

98
   secure_vector<gf2m> result(d);
212✔
99
   for(uint32_t i = 0; i < d; ++i) {
14,056✔
100
      const gf2m current = res[i];
13,844✔
101

102
      const gf2m tmp = gray_to_lex(current);
13,844✔
103
      if(tmp >= code_length) /* invalid root */
13,844✔
104
      {
105
         result[i] = static_cast<gf2m>(i);
×
106
      } else {
107
         result[i] = Linv[tmp];
13,844✔
108
      }
109
   }
110

111
   return result;
212✔
112
}
848✔
113
}  // namespace
114

115
void mceliece_decrypt(secure_vector<uint8_t>& plaintext_out,
6✔
116
                      secure_vector<uint8_t>& error_mask_out,
117
                      const secure_vector<uint8_t>& ciphertext,
118
                      const McEliece_PrivateKeyInternal& key) {
119
   mceliece_decrypt(plaintext_out, error_mask_out, ciphertext.data(), ciphertext.size(), key);
6✔
120
}
6✔
121

122
void mceliece_decrypt(secure_vector<uint8_t>& plaintext,
212✔
123
                      secure_vector<uint8_t>& error_mask,
124
                      const uint8_t ciphertext[],
125
                      size_t ciphertext_len,
126
                      const McEliece_PrivateKeyInternal& key) {
127
   secure_vector<gf2m> error_pos;
212✔
128
   plaintext = mceliece_decrypt(error_pos, ciphertext, ciphertext_len, key);
424✔
129

130
   const size_t code_length = key.code_length();
212✔
131
   secure_vector<uint8_t> result((code_length + 7) / 8);
212✔
132
   for(auto&& pos : error_pos) {
14,056✔
133
      if(pos >= code_length) {
13,844✔
134
         throw Invalid_Argument("error position larger than code size");
×
135
      }
136
      result[pos / 8] |= (1 << (pos % 8));
13,844✔
137
   }
138

139
   error_mask = result;
212✔
140
}
424✔
141

142
/**
143
* @p p_err_pos_len must point to the available length of @p error_pos on input, the
144
* function will set it to the actual number of errors returned in the @p error_pos
145
* array */
146
secure_vector<uint8_t> mceliece_decrypt(secure_vector<gf2m>& error_pos,
212✔
147
                                        const uint8_t* ciphertext,
148
                                        size_t ciphertext_len,
149
                                        const McEliece_PrivateKeyInternal& key) {
150
   const size_t dimension = key.dimension();
212✔
151
   const size_t codimension = key.codimension();
212✔
152
   const uint32_t t = key.goppa_polyn().get_degree();
212✔
153
   polyn_gf2m syndrome_polyn(key.goppa_polyn().get_sp_field());  // init as zero polyn
212✔
154
   const unsigned unused_pt_bits = dimension % 8;
212✔
155
   const uint8_t unused_pt_bits_mask = (1 << unused_pt_bits) - 1;
212✔
156

157
   if(ciphertext_len != (key.code_length() + 7) / 8) {
212✔
158
      throw Invalid_Argument("wrong size of McEliece ciphertext");
×
159
   }
160
   const size_t cleartext_len = (key.message_word_bit_length() + 7) / 8;
212✔
161

162
   if(cleartext_len != bit_size_to_byte_size(dimension)) {
212✔
163
      throw Invalid_Argument("mce-decryption: wrong length of cleartext buffer");
×
164
   }
165

166
   secure_vector<uint32_t> syndrome_vec(bit_size_to_32bit_size(codimension));
212✔
167
   matrix_arr_mul(key.H_coeffs(),
212✔
168
                  key.code_length(),
169
                  bit_size_to_32bit_size(codimension),
170
                  ciphertext,
171
                  syndrome_vec.data(),
172
                  syndrome_vec.size());
173

174
   secure_vector<uint8_t> syndrome_byte_vec(bit_size_to_byte_size(codimension));
212✔
175
   const size_t syndrome_byte_vec_size = syndrome_byte_vec.size();
212✔
176
   for(size_t i = 0; i < syndrome_byte_vec_size; i++) {
21,708✔
177
      syndrome_byte_vec[i] = static_cast<uint8_t>(syndrome_vec[i / 4] >> (8 * (i % 4)));
21,496✔
178
   }
179

180
   syndrome_polyn =
212✔
181
      polyn_gf2m(t - 1, syndrome_byte_vec.data(), bit_size_to_byte_size(codimension), key.goppa_polyn().get_sp_field());
424✔
182

183
   syndrome_polyn.get_degree();
212✔
184
   error_pos = goppa_decode(syndrome_polyn, key.goppa_polyn(), key.sqrtmod(), key.Linv());
424✔
185

186
   const size_t nb_err = error_pos.size();
212✔
187

188
   secure_vector<uint8_t> cleartext(cleartext_len);
212✔
189
   copy_mem(cleartext.data(), ciphertext, cleartext_len);
212✔
190

191
   for(size_t i = 0; i < nb_err; i++) {
14,056✔
192
      const gf2m current = error_pos[i];
13,844✔
193

194
      if(current >= cleartext_len * 8) {
13,844✔
195
         // an invalid position, this shouldn't happen
196
         continue;
3,212✔
197
      }
198
      cleartext[current / 8] ^= (1 << (current % 8));
10,632✔
199
   }
200

201
   if(unused_pt_bits > 0) {
212✔
202
      cleartext[cleartext_len - 1] &= unused_pt_bits_mask;
212✔
203
   }
204

205
   return cleartext;
424✔
206
}
424✔
207

208
}  // namespace Botan
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc