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

randombit / botan / 16242160666

12 Jul 2025 09:23PM UTC coverage: 90.573%. Remained the same
16242160666

push

github

web-flow
Merge pull request #4973 from randombit/jack/fix-clang-tidy-cppcoreguidelines-avoid-do-while

Enable and fix clang-tidy warning cppcoreguidelines-avoid-do-while

99084 of 109397 relevant lines covered (90.57%)

12472299.98 hits per line

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

96.55
/src/lib/pubkey/mce/code_based_key_gen.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
 * (C) 2015 Jack Lloyd
8
 *
9
 * Botan is released under the Simplified BSD License (see license.txt)
10
 *
11
 */
12

13
#include <botan/mceliece.h>
14

15
#include <botan/internal/code_based_util.h>
16
#include <botan/internal/loadstor.h>
17
#include <botan/internal/mce_internal.h>
18
#include <botan/internal/polyn_gf2m.h>
19

20
namespace Botan {
21

22
namespace {
23

24
class binary_matrix final {
186✔
25
   public:
26
      binary_matrix(size_t m_rown, size_t m_coln);
27

28
      void row_xor(size_t a, size_t b);
29
      secure_vector<size_t> row_reduced_echelon_form();
30

31
      /**
32
      * return the coefficient out of F_2
33
      */
34
      uint32_t coef(size_t i, size_t j) { return (m_elem[(i)*m_rwdcnt + (j) / 32] >> (j % 32)) & 1; }
83,361,466✔
35

36
      void set_coef_to_one(size_t i, size_t j) {
54,274,404✔
37
         m_elem[(i)*m_rwdcnt + (j) / 32] |= (static_cast<uint32_t>(1) << ((j) % 32));
54,274,404✔
38
      }
54,274,404✔
39

40
      void toggle_coeff(size_t i, size_t j) {
41,678,016✔
41
         m_elem[(i)*m_rwdcnt + (j) / 32] ^= (static_cast<uint32_t>(1) << ((j) % 32));
41,678,016✔
42
      }
41,678,016✔
43

44
      size_t rows() const { return m_rown; }
108,169✔
45

46
      size_t columns() const { return m_coln; }
83,469,542✔
47

48
      const std::vector<uint32_t>& elem() const { return m_elem; }
2,658,601✔
49

50
   private:
51
      size_t m_rown;    // number of rows.
52
      size_t m_coln;    // number of columns.
53
      size_t m_rwdcnt;  // number of words in a row
54
      std::vector<uint32_t> m_elem;
55
};
56

57
binary_matrix::binary_matrix(size_t rown, size_t coln) {
186✔
58
   m_coln = coln;
186✔
59
   m_rown = rown;
186✔
60
   m_rwdcnt = 1 + ((m_coln - 1) / 32);
186✔
61
   m_elem = std::vector<uint32_t>(m_rown * m_rwdcnt);
186✔
62
}
186✔
63

64
void binary_matrix::row_xor(size_t a, size_t b) {
65
   for(size_t i = 0; i != m_rwdcnt; i++) {
1,937,918,652✔
66
      m_elem[a * m_rwdcnt + i] ^= m_elem[b * m_rwdcnt + i];
1,925,322,309✔
67
   }
68
}
69

70
//the matrix is reduced from LSB...(from right)
71
secure_vector<size_t> binary_matrix::row_reduced_echelon_form() {
93✔
72
   secure_vector<size_t> perm(m_coln);
93✔
73
   for(size_t i = 0; i != m_coln; i++) {
142,605✔
74
      perm[i] = i;  // initialize permutation.
142,512✔
75
   }
76

77
   uint32_t failcnt = 0;
93✔
78

79
   size_t max = m_coln - 1;
93✔
80
   for(size_t i = 0; i != m_rown; i++, max--) {
34,730✔
81
      bool found_row = false;
82

83
      for(size_t j = i; !found_row && j != m_rown; j++) {
103,483✔
84
         if(coef(j, max)) {
68,846✔
85
            if(i != j)  //not needed as ith row is 0 and jth row is 1.
34,436✔
86
            {
87
               row_xor(i, j);  //xor to the row.(swap)?
68,846✔
88
            }
89

90
            found_row = true;
91
         }
92
      }
93

94
      //if no row with a 1 found then swap last column and the column with no 1 down.
95
      if(!found_row) {
34,637✔
96
         perm[m_coln - m_rown - 1 - failcnt] = static_cast<int>(max);
201✔
97
         failcnt++;
201✔
98
         if(!max) {
201✔
99
            perm.clear();
×
100
         }
101
         i--;
201✔
102
      } else {
103
         perm[i + m_coln - m_rown] = max;
34,436✔
104
         for(size_t j = i + 1; j < m_rown; j++)  //fill the column downwards with 0's
12,614,061✔
105
         {
106
            if(coef(j, max)) {
12,579,625✔
107
               row_xor(j, i);  //check the arg. order.
12,579,625✔
108
            }
109
         }
110

111
         //fill the column with 0's upwards too.
112
         for(size_t j = i; j != 0; --j) {
12,614,061✔
113
            if(coef(j - 1, max)) {
12,579,625✔
114
               row_xor(j - 1, i);
12,614,061✔
115
            }
116
         }
117
      }
118
   }  //end for(i)
119
   return perm;
93✔
120
}
121

122
void randomize_support(std::vector<gf2m>& L, RandomNumberGenerator& rng) {
93✔
123
   for(size_t i = 0; i != L.size(); ++i) {
142,605✔
124
      gf2m rnd = random_gf2m(rng);
142,512✔
125

126
      // no rejection sampling, but for useful code-based parameters with n <= 13 this seem tolerable
127
      std::swap(L[i], L[rnd % L.size()]);
142,512✔
128
   }
129
}
93✔
130

131
std::unique_ptr<binary_matrix> generate_R(
93✔
132
   std::vector<gf2m>& L, polyn_gf2m* g, const GF2m_Field& sp_field, size_t code_length, size_t t) {
133
   //L- Support
134
   //t- Number of errors
135
   //n- Length of the Goppa code
136
   //m- The extension degree of the GF
137
   //g- The generator polynomial.
138

139
   const size_t r = t * sp_field.get_extension_degree();
93✔
140

141
   binary_matrix H(r, code_length);
93✔
142

143
   for(size_t i = 0; i != code_length; i++) {
142,605✔
144
      gf2m x = g->eval(lex_to_gray(L[i]));  //evaluate the polynomial at the point L[i].
142,512✔
145
      x = sp_field.gf_inv(x);
142,512✔
146
      gf2m y = x;
147
      for(size_t j = 0; j < t; j++) {
9,026,112✔
148
         for(size_t k = 0; k < sp_field.get_extension_degree(); k++) {
117,438,752✔
149
            if(y & (1 << k)) {
108,555,152✔
150
               //the co-eff. are set in 2^0,...,2^11 ; 2^0,...,2^11 format along the rows/cols?
151
               H.set_coef_to_one(j * sp_field.get_extension_degree() + k, i);
54,274,404✔
152
            }
153
         }
154
         y = sp_field.gf_mul(y, lex_to_gray(L[i]));
17,764,166✔
155
      }
156
   }  //The H matrix is fed.
157

158
   secure_vector<size_t> perm = H.row_reduced_echelon_form();
93✔
159
   if(perm.empty()) {
93✔
160
      throw Invalid_State("McEliece keygen failed - could not bring matrix to row reduced echelon form");
×
161
   }
162

163
   auto result = std::make_unique<binary_matrix>(code_length - r, r);
93✔
164
   for(size_t i = 0; i < result->rows(); ++i) {
108,169✔
165
      for(size_t j = 0; j < result->columns(); ++j) {
83,469,542✔
166
         if(H.coef(j, perm[i])) {
83,361,466✔
167
            result->toggle_coeff(i, j);
41,678,016✔
168
         }
169
      }
170
   }
171

172
   std::vector<gf2m> Laux(code_length);
93✔
173
   for(size_t i = 0; i < code_length; ++i) {
142,605✔
174
      Laux[i] = L[perm[i]];
142,512✔
175
   }
176

177
   for(size_t i = 0; i < code_length; ++i) {
142,605✔
178
      L[i] = Laux[i];
142,512✔
179
   }
180
   return result;
93✔
181
}
279✔
182
}  // namespace
183

184
McEliece_PrivateKey generate_mceliece_key(RandomNumberGenerator& rng, size_t ext_deg, size_t code_length, size_t t) {
93✔
185
   const size_t codimension = t * ext_deg;
93✔
186

187
   if(code_length <= codimension) {
93✔
188
      throw Invalid_Argument("invalid McEliece parameters");
×
189
   }
190

191
   auto sp_field = std::make_shared<GF2m_Field>(ext_deg);
93✔
192

193
   //pick the support.........
194
   std::vector<gf2m> L(code_length);
93✔
195

196
   for(size_t i = 0; i != L.size(); i++) {
142,605✔
197
      L[i] = static_cast<gf2m>(i);
142,512✔
198
   }
199
   randomize_support(L, rng);
93✔
200
   polyn_gf2m g(sp_field);  // create as zero
93✔
201

202
   bool success = false;
93✔
203
   std::unique_ptr<binary_matrix> R;
93✔
204

205
   // NOLINTNEXTLINE(*-avoid-do-while)
206
   do {
93✔
207
      // create a random irreducible polynomial
208
      g = polyn_gf2m(t, rng, sp_field);
186✔
209

210
      try {
93✔
211
         R = generate_R(L, &g, *sp_field, code_length, t);
186✔
212
         success = true;
93✔
213
      } catch(const Invalid_State&) {}
×
214
   } while(!success);
93✔
215

216
   std::vector<polyn_gf2m> sqrtmod = polyn_gf2m::sqrt_mod_init(g);
93✔
217
   std::vector<polyn_gf2m> F = syndrome_init(g, L, static_cast<int>(code_length));
93✔
218

219
   // Each F[i] is the (precomputed) syndrome of the error vector with
220
   // a single '1' in i-th position.
221
   // We do not store the F[i] as polynomials of degree t , but
222
   // as binary vectors of length ext_deg * t (this will
223
   // speed up the syndrome computation)
224
   //
225
   const size_t co32 = bit_size_to_32bit_size(codimension);
93✔
226
   std::vector<uint32_t> H(co32 * code_length);
93✔
227
   uint32_t* sk = H.data();
93✔
228
   for(size_t i = 0; i < code_length; ++i) {
142,605✔
229
      for(size_t l = 0; l < t; ++l) {
9,026,112✔
230
         const size_t k = (l * ext_deg) / 32;
8,883,600✔
231
         const size_t j = (l * ext_deg) % 32;
8,883,600✔
232
         sk[k] ^= static_cast<uint32_t>(F[i].get_coef(l)) << j;
8,883,600✔
233
         if(j + ext_deg > 32) {
8,883,600✔
234
            if(j > 0) {
3,021,728✔
235
               sk[k + 1] ^= F[i].get_coef(l) >> (32 - j);
3,021,728✔
236
            }
237
         }
238
      }
239
      sk += co32;
142,512✔
240
   }
241

242
   // We need the support L for decoding (decryption). In fact the
243
   // inverse is needed
244

245
   std::vector<gf2m> Linv(code_length);
93✔
246
   for(size_t i = 0; i != Linv.size(); ++i) {
142,605✔
247
      Linv[L[i]] = static_cast<gf2m>(i);
142,512✔
248
   }
249
   std::vector<uint8_t> pubmat(R->elem().size() * 4);
93✔
250
   for(size_t i = 0; i < R->elem().size(); i++) {
2,658,508✔
251
      store_le(R->elem()[i], &pubmat[i * 4]);
2,658,415✔
252
   }
253

254
   return McEliece_PrivateKey(g, H, sqrtmod, Linv, pubmat);
93✔
255
}
465✔
256

257
}  // 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