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

randombit / botan / 11844561993

14 Nov 2024 07:58PM UTC coverage: 91.178% (+0.1%) from 91.072%
11844561993

Pull #4435

github

web-flow
Merge 81dcb29da into e430f157a
Pull Request #4435: Test duration values ​​are now presented in seconds with six digits of precision. Tests without time measurements have been edited.

91856 of 100744 relevant lines covered (91.18%)

9311006.71 hits per line

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

98.26
/src/tests/test_ct_utils.cpp
1
/*
2
* (C) 2018,2024 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6

7
#include "tests.h"
8
#include <botan/internal/ct_utils.h>
9
#include <botan/internal/fmt.h>
10

11
namespace Botan_Tests {
12

13
class CT_Mask_Tests final : public Test {
×
14
   public:
15
      std::vector<Test::Result> run() override {
1✔
16
         Test::Result result("CT::Mask");
1✔
17
         result.start_timer();
1✔
18

19
         result.test_eq_sz("CT::is_zero8", Botan::CT::Mask<uint8_t>::is_zero(0).value(), 0xFF);
1✔
20
         result.test_eq_sz("CT::is_zero8", Botan::CT::Mask<uint8_t>::is_zero(1).value(), 0x00);
1✔
21
         result.test_eq_sz("CT::is_zero8", Botan::CT::Mask<uint8_t>::is_zero(0xFF).value(), 0x00);
1✔
22

23
         result.test_eq_sz("CT::is_zero16", Botan::CT::Mask<uint16_t>::is_zero(0).value(), 0xFFFF);
1✔
24
         result.test_eq_sz("CT::is_zero16", Botan::CT::Mask<uint16_t>::is_zero(1).value(), 0x0000);
1✔
25
         result.test_eq_sz("CT::is_zero16", Botan::CT::Mask<uint16_t>::is_zero(0xFF).value(), 0x0000);
1✔
26

27
         result.test_eq_sz("CT::is_zero32", Botan::CT::Mask<uint32_t>::is_zero(0).value(), 0xFFFFFFFF);
1✔
28
         result.test_eq_sz("CT::is_zero32", Botan::CT::Mask<uint32_t>::is_zero(1).value(), 0x00000000);
1✔
29
         result.test_eq_sz("CT::is_zero32", Botan::CT::Mask<uint32_t>::is_zero(0xFF).value(), 0x00000000);
1✔
30

31
         result.test_eq_sz("CT::is_less8", Botan::CT::Mask<uint8_t>::is_lt(0, 1).value(), 0xFF);
1✔
32
         result.test_eq_sz("CT::is_less8", Botan::CT::Mask<uint8_t>::is_lt(1, 0).value(), 0x00);
1✔
33
         result.test_eq_sz("CT::is_less8", Botan::CT::Mask<uint8_t>::is_lt(0xFF, 5).value(), 0x00);
1✔
34

35
         result.test_eq_sz("CT::is_less16", Botan::CT::Mask<uint16_t>::is_lt(0, 1).value(), 0xFFFF);
1✔
36
         result.test_eq_sz("CT::is_less16", Botan::CT::Mask<uint16_t>::is_lt(1, 0).value(), 0x0000);
1✔
37
         result.test_eq_sz("CT::is_less16", Botan::CT::Mask<uint16_t>::is_lt(0xFFFF, 5).value(), 0x0000);
1✔
38

39
         result.test_eq_sz("CT::is_less32", Botan::CT::Mask<uint32_t>::is_lt(0, 1).value(), 0xFFFFFFFF);
1✔
40
         result.test_eq_sz("CT::is_less32", Botan::CT::Mask<uint32_t>::is_lt(1, 0).value(), 0x00000000);
1✔
41
         result.test_eq_sz("CT::is_less32", Botan::CT::Mask<uint32_t>::is_lt(0xFFFF5, 5).value(), 0x00000000);
1✔
42
         result.test_eq_sz("CT::is_less32", Botan::CT::Mask<uint32_t>::is_lt(0xFFFFFFFF, 5).value(), 0x00000000);
1✔
43
         result.test_eq_sz("CT::is_less32", Botan::CT::Mask<uint32_t>::is_lt(5, 0xFFFFFFFF).value(), 0xFFFFFFFF);
1✔
44

45
         for(auto bad_input : {0, 1}) {
3✔
46
            for(size_t input_length = 0; input_length != 64; ++input_length) {
130✔
47
               for(size_t offset = 0; offset != input_length + 5; ++offset) {
4,800✔
48
                  const auto accept = !Botan::CT::Choice::from_int(static_cast<uint32_t>(bad_input));
4,672✔
49

50
                  std::vector<uint8_t> input(input_length);
4,672✔
51
                  this->rng().randomize(input.data(), input.size());
4,672✔
52

53
                  std::vector<uint8_t> output(input_length);
4,672✔
54

55
                  auto written = Botan::CT::copy_output(accept, output, input, offset);
4,672✔
56

57
                  if(bad_input) {
4,672✔
58
                     result.confirm("If bad input, no output", !written.has_value().as_bool());
4,672✔
59
                  } else {
60
                     if(offset > input_length) {
2,336✔
61
                        result.confirm("If offset is too large, no output", !written.has_value().as_bool());
512✔
62
                     } else {
63
                        const size_t bytes = written.value();
2,080✔
64
                        result.test_eq_sz("CT::copy_output length", bytes, input.size() - offset);
2,080✔
65

66
                        for(size_t i = 0; i != bytes; ++i) {
45,760✔
67
                           result.test_eq_sz("CT::copy_output offset", output[i], input[i + offset]);
87,360✔
68
                        }
69
                     }
70
                  }
71
               }
9,334✔
72
            }
73
         }
74

75
         result.end_timer();
1✔
76
         return {result};
3✔
77
      }
2✔
78
};
79

80
BOTAN_REGISTER_TEST("ct_utils", "ct_mask", CT_Mask_Tests);
81

82
class CT_Choice_Tests final : public Test {
×
83
   public:
84
      std::vector<Test::Result> run() override {
1✔
85
         Test::Result result("CT::Choice");
1✔
86
         result.start_timer();
1✔
87

88
         result.test_eq("CT::Choice::yes", Botan::CT::Choice::yes().as_bool(), true);
1✔
89
         result.test_eq("CT::Choice::no", Botan::CT::Choice::no().as_bool(), false);
1✔
90

91
         test_choice_from_int<uint8_t>("uint8_t", result);
1✔
92
         test_choice_from_int<uint16_t>("uint16_t", result);
1✔
93
         test_choice_from_int<uint32_t>("uint32_t", result);
1✔
94
         test_choice_from_int<uint64_t>("uint64_t", result);
1✔
95

96
         result.end_timer();
1✔
97
         return {result};
3✔
98
      }
2✔
99

100
   private:
101
      template <std::unsigned_integral T>
102
      void test_choice_from_int(const char* type_name, Result& result) {
4✔
103
         const auto tname = Botan::fmt("CT::Choice::from_int<{}>", type_name);
4✔
104
         constexpr size_t tbits = sizeof(T) * 8;
4✔
105

106
         result.test_eq(tname, Botan::CT::Choice::from_int<T>(0).as_bool(), false);
4✔
107
         for(size_t b = 0; b != tbits; ++b) {
124✔
108
            const auto choice = Botan::CT::Choice::from_int<T>(static_cast<T>(1) << b);
120✔
109
            result.test_eq(tname, choice.as_bool(), true);
120✔
110
         }
111
      }
4✔
112
};
113

114
BOTAN_REGISTER_TEST("ct_utils", "ct_choice", CT_Choice_Tests);
115

116
class CT_Option_Tests final : public Test {
×
117
   public:
118
      std::vector<Test::Result> run() override {
1✔
119
         Test::Result result("CT::Option");
1✔
120
         result.start_timer();
1✔
121

122
         class Val {
1✔
123
            public:
124
               Val() : m_val() {}
5✔
125

126
               Val(uint8_t x) : m_val{x, x, x, x} {}
1✔
127

128
               void conditional_assign(Botan::CT::Choice choice, const Val& other) {
3✔
129
                  Botan::CT::conditional_assign_mem(choice, m_val, other.m_val, 4);
6✔
130
               }
131

132
               bool operator==(const Val& other) const { return std::memcmp(m_val, other.m_val, 4) == 0; }
1✔
133

134
               Val& operator++() {
1✔
135
                  // totally arbitrary here ...
136
                  m_val[0] += 1;
2✔
137
                  return (*this);
1✔
138
               }
139

140
            private:
141
               uint8_t m_val[4];
142
         };
143

144
         test_ct_option<Val>(result, Val(42), Val(23));
1✔
145
         test_ct_option<uint8_t>(result, 42, 23);
1✔
146
         test_ct_option<uint16_t>(result, 4242, 2323);
1✔
147
         test_ct_option<uint32_t>(result, 42424242, 23232323);
1✔
148
         test_ct_option<uint64_t>(result, 4242424242424242, 2323232323232323);
1✔
149

150
         result.end_timer();
1✔
151
         return {result};
3✔
152
      }
2✔
153

154
   private:
155
      template <typename T>
156
      void test_ct_option(Test::Result& result, const T& value, const T& value2) {
5✔
157
         auto unset = Botan::CT::Option<T>();
5✔
158
         result.test_eq("Unset does not have value", unset.has_value().as_bool(), false);
5✔
159
         result.test_throws("Unset Option throws if value is called", [&]() { unset.value(); });
16✔
160
         result.confirm("Unset Option returns alternative with value_or", unset.value_or(value) == value);
10✔
161
         result.confirm("Unset Option returns alternative with value_or", unset.value_or(value2) == value2);
10✔
162
         result.confirm(
10✔
163
            "Unset Option returns nullopt for as_optional_vartime", unset.as_optional_vartime().has_value(), false);
10✔
164

165
         auto next = [](const T& v) -> T {
5✔
166
            T n = v;
10✔
167
            ++n;
2✔
168
            return n;
1✔
169
         };
170

171
         result.test_eq("Unset Option transform returns unset", unset.transform(next).has_value().as_bool(), false);
6✔
172

173
         auto set = Botan::CT::Option<T>(value);
5✔
174
         result.test_eq("Set does have value", set.has_value().as_bool(), true);
10✔
175
         result.confirm("Set Option has the expected value", set.value() == value);
10✔
176
         result.confirm("Set Option returns original with value_or", set.value_or(value2) == value);
10✔
177
         result.confirm("Set Option returns something for as_optional_vartime",
10✔
178
                        set.as_optional_vartime().value() == value);
9✔
179

180
         result.confirm("Set Option transform returns set", set.transform(next).value() == next(value));
10✔
181
      }
5✔
182
};
183

184
BOTAN_REGISTER_TEST("ct_utils", "ct_option", CT_Option_Tests);
185

186
namespace {
187

188
template <typename T = void>
189
struct Poisonable {
10✔
190
      mutable bool poisoned = false;  // NOLINT(misc-non-private-member-variables-in-classes)
191

192
      void _const_time_poison() const { poisoned = true; }
11✔
193

194
      void _const_time_unpoison() const { poisoned = false; }
11✔
195
};
196

197
std::vector<Test::Result> test_higher_level_ct_poison() {
1✔
198
   return {
1✔
199
      CHECK("custom poisonable object",
200
            [](Test::Result& result) {
1✔
201
               result.start_timer();
1✔
202
               Poisonable p;
1✔
203
               result.confirm("not poisoned", p.poisoned == false);
2✔
204
               Botan::CT::poison(p);
1✔
205
               result.confirm("poisoned", p.poisoned == true);
2✔
206
               Botan::CT::unpoison(p);
1✔
207
               result.confirm("unpoisoned", p.poisoned == false);
2✔
208
               result.end_timer();
1✔
209
            }),
1✔
210

211
      CHECK("poison multiple objects",
212
            [](Test::Result& result) {
1✔
213
               result.start_timer();
1✔
214
               // template is useless, but p1, p2, and p3 are different types and we
215
               // want to make sure that poison_all/unpoison_all can deal with that.
216
               Poisonable<int> p1;
1✔
217
               Poisonable<double> p2;
1✔
218
               Poisonable<std::string> p3;
1✔
219

220
               result.confirm("all not poisoned", !p1.poisoned && !p2.poisoned && !p3.poisoned);
2✔
221
               Botan::CT::poison_all(p1, p2, p3);
1✔
222
               result.confirm("all poisoned", p1.poisoned && p2.poisoned && p3.poisoned);
2✔
223
               Botan::CT::unpoison_all(p1, p2, p3);
1✔
224
               result.confirm("all unpoisoned", !p1.poisoned && !p2.poisoned && !p3.poisoned);
2✔
225
               result.end_timer();
1✔
226
            }),
1✔
227

228
      CHECK("scoped poison",
229
            [](Test::Result& result) {
1✔
230
               result.start_timer();
1✔
231
               // template is useless, but p1, p2, and p3 are different types and we
232
               // want to make sure that poison_all/unpoison_all can deal with that.
233
               Poisonable<int> p1;
1✔
234
               Poisonable<double> p2;
1✔
235
               Poisonable<std::string> p3;
1✔
236

237
               result.confirm("not poisoned", !p1.poisoned && !p2.poisoned, !p3.poisoned);
2✔
238

239
               {
1✔
240
                  auto scope = Botan::CT::scoped_poison(p1, p2, p3);
1✔
241
                  result.confirm("poisoned", p1.poisoned && p2.poisoned && p3.poisoned);
2✔
242
               }
1✔
243

244
               result.confirm("unpoisoned", !p1.poisoned && !p2.poisoned && !p3.poisoned);
2✔
245
               result.end_timer();
1✔
246
            }),
1✔
247

248
      CHECK("poison a range of poisonable objects",
249
            [](Test::Result& result) {
1✔
250
               result.start_timer();
1✔
251

252
               auto is_poisoned = [](const auto& p) { return p.poisoned; };
12✔
253

254
               std::vector<Poisonable<>> v(10);
1✔
255
               result.confirm("none poisoned", std::none_of(v.begin(), v.end(), is_poisoned));
2✔
256

257
               Botan::CT::poison_range(v);
1✔
258
               result.confirm("all poisoned", std::all_of(v.begin(), v.end(), is_poisoned));
2✔
259

260
               Botan::CT::unpoison_range(v);
1✔
261
               result.confirm("all unpoisoned", std::none_of(v.begin(), v.end(), is_poisoned));
2✔
262

263
               result.end_timer();
1✔
264
            }),
1✔
265

266
      CHECK("poison a poisonable objects with driveby_poison",
267
            [](Test::Result& result) {
1✔
268
               result.start_timer();
1✔
269

270
               Poisonable p;
1✔
271
               result.confirm("not poisoned", p.poisoned == false);
2✔
272
               Poisonable p_poisoned =
1✔
273
                  Botan::CT::driveby_poison(std::move(p));  // NOLINT(hicpp-move-const-arg,performance-move-const-arg)
1✔
274
               result.confirm("poisoned", p_poisoned.poisoned == true);
2✔
275
               Poisonable p_unpoisoned = Botan::CT::driveby_unpoison(
1✔
276
                  std::move(p_poisoned));  // NOLINT(hicpp-move-const-arg,performance-move-const-arg)
1✔
277
               result.confirm("unpoisoned", p_unpoisoned.poisoned == false);
2✔
278
               
279
               result.end_timer();
1✔
280
            }),
1✔
281
   };
6✔
282
}
1✔
283

284
}  // namespace
285

286
BOTAN_REGISTER_TEST_FN("ct_utils", "ct_poison", test_higher_level_ct_poison);
287

288
}  // namespace Botan_Tests
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

© 2025 Coveralls, Inc