Coverage Report

Created: 2025-04-11 06:34

/src/botan/src/lib/pubkey/mce/mce_workfactor.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
 * (C) 2014 Jack Lloyd
5
 *
6
 * Botan is released under the Simplified BSD License (see license.txt)
7
 *
8
 */
9
10
#include <botan/mceliece.h>
11
12
#include <botan/internal/bit_ops.h>
13
#include <cmath>
14
#include <numbers>
15
16
namespace Botan {
17
18
namespace {
19
20
0
double binomial(size_t n, size_t k) {
21
0
   double x = 1;
22
23
0
   for(size_t i = 0; i != k; ++i) {
24
0
      x *= n - i;
25
0
      x /= k - i;
26
0
   }
27
28
0
   return x;
29
0
}
30
31
0
double log_binomial(size_t n, size_t k) {
32
0
   double x = 0;
33
34
0
   for(size_t i = 0; i != k; ++i) {
35
0
      x += std::log(n - i);
36
0
      x -= std::log(k - i);
37
0
   }
38
39
0
   return x / std::numbers::ln2;
40
0
}
41
42
0
double nb_iter(size_t n, size_t k, size_t w, size_t p, size_t l) {
43
0
   double x = 2 * log_binomial(k / 2, p);
44
0
   x += log_binomial(n - k - l, w - 2 * p);
45
0
   x = log_binomial(n, w) - x;
46
0
   return x;
47
0
}
48
49
0
double cout_iter(size_t n, size_t k, size_t p, size_t l) {
50
0
   double x = binomial(k / 2, p);
51
0
   const size_t i = static_cast<size_t>(std::log(x) / std::numbers::ln2);
52
0
   double res = 2 * p * (n - k - l) * std::ldexp(x * x, -static_cast<int>(l));
53
54
   // x <- binomial(k/2,p)*2*(2*l+log[2](binomial(k/2,p)))
55
0
   x *= 2 * (2 * l + i);
56
57
   // res <- k*(n-k)/2 +
58
   // binomial(k/2,p)*2*(2*l+log[2](binomial(k/2,p))) +
59
   // 2*p*(n-k-l)*binomial(k/2,p)^2/2^l
60
0
   res += x + k * ((n - k) / 2.0);
61
62
0
   return std::log(res) / std::numbers::ln2;  // convert to bits
63
0
}
64
65
0
double cout_total(size_t n, size_t k, size_t w, size_t p, size_t l) {
66
0
   return nb_iter(n, k, w, p, l) + cout_iter(n, k, p, l);
67
0
}
68
69
0
double best_wf(size_t n, size_t k, size_t w, size_t p) {
70
0
   if(p >= k / 2) {
71
0
      return -1;
72
0
   }
73
74
0
   double min = cout_total(n, k, w, p, 0);
75
76
0
   for(size_t l = 1; l < n - k; ++l) {
77
0
      const double lwf = cout_total(n, k, w, p, l);
78
0
      if(lwf < min) {
79
0
         min = lwf;
80
0
      } else {
81
0
         break;
82
0
      }
83
0
   }
84
85
0
   return min;
86
0
}
87
88
}  // namespace
89
90
0
size_t mceliece_work_factor(size_t n, size_t t) {
91
0
   const size_t k = n - ceil_log2(n) * t;
92
93
0
   double min = cout_total(n, k, t, 0, 0);  // correspond a p=1
94
0
   for(size_t p = 0; p != t / 2; ++p) {
95
0
      double lwf = best_wf(n, k + 1, t, p);
96
0
      if(lwf < 0) {
97
0
         break;
98
0
      }
99
100
0
      min = std::min(min, lwf);
101
0
   }
102
103
0
   return static_cast<size_t>(min);
104
0
}
105
106
}  // namespace Botan