/src/botan/build/include/botan/internal/keccak_helpers.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Helper functions to implement Keccak-derived functions from NIST SP.800-185 |
3 | | * (C) 2023 Jack Lloyd |
4 | | * (C) 2023 René Meusel - Rohde & Schwarz Cybersecurity |
5 | | * |
6 | | * Botan is released under the Simplified BSD License (see license.txt) |
7 | | */ |
8 | | |
9 | | #ifndef BOTAN_KECCAK_HELPERS_H_ |
10 | | #define BOTAN_KECCAK_HELPERS_H_ |
11 | | |
12 | | #include <array> |
13 | | #include <cstdint> |
14 | | #include <span> |
15 | | |
16 | | #include <botan/assert.h> |
17 | | #include <botan/concepts.h> |
18 | | |
19 | | namespace Botan { |
20 | | |
21 | | /** |
22 | | * Integer encoding defined in NIST SP.800-185 that can be unambiguously |
23 | | * parsed from the beginning of the string. |
24 | | * |
25 | | * This function does not allocate any memory and requires the caller to |
26 | | * provide a sufficiently large @p buffer. For a given @p x, this will |
27 | | * need exactly keccak_int_encoding_size() bytes. For an arbitrary @p x |
28 | | * it will generate keccak_max_int_encoding_size() bytes at most. |
29 | | * |
30 | | * @param buffer buffer to write the left-encoding of @p x to. |
31 | | * It is assumed that the buffer will hold at least |
32 | | * keccak_int_encoding_size() bytes. |
33 | | * @param x the integer to be left-encoded |
34 | | * @return the byte span that represents the bytes written to @p buffer. |
35 | | */ |
36 | | BOTAN_TEST_API std::span<const uint8_t> keccak_int_left_encode(std::span<uint8_t> buffer, size_t x); |
37 | | |
38 | | /** |
39 | | * Integer encoding defined in NIST SP.800-185 that can be unambiguously |
40 | | * parsed from the end of the string. |
41 | | * |
42 | | * This function does not allocate any memory and requires the caller to |
43 | | * provide a sufficiently large @p buffer. For a given @p x, this will |
44 | | * need exactly keccak_int_encoding_size() bytes. For an arbitrary @p x |
45 | | * it will generate keccak_max_int_encoding_size() bytes at most. |
46 | | * |
47 | | * @param out buffer to write the right-encoding of @p x to. |
48 | | * It is assumed that the buffer will hold at least |
49 | | * keccak_int_encoding_size() bytes. |
50 | | * @param x the integer to be right-encoded |
51 | | * @return the byte span that represents the bytes written to @p buffer. |
52 | | */ |
53 | | BOTAN_TEST_API std::span<const uint8_t> keccak_int_right_encode(std::span<uint8_t> out, size_t x); |
54 | | |
55 | | /** |
56 | | * @returns the required bytes for encodings of keccak_int_left_encode() or |
57 | | * keccak_int_right_encode() given an integer @p x |
58 | | */ |
59 | | BOTAN_TEST_API size_t keccak_int_encoding_size(size_t x); |
60 | | |
61 | | /** |
62 | | * @returns the maximum required bytes for encodings of keccak_int_left_encode() or |
63 | | * keccak_int_right_encode() |
64 | | */ |
65 | 0 | constexpr size_t keccak_max_int_encoding_size() { |
66 | 0 | return sizeof(size_t) + 1 /* the length tag */; |
67 | 0 | } |
68 | | |
69 | | template <typename T> |
70 | | concept updatable_object = requires(T& a, std::span<const uint8_t> span) { a.update(span); }; |
71 | | |
72 | | template <typename T> |
73 | | concept appendable_object = requires(T& a, std::span<const uint8_t> s) { a.insert(a.end(), s.begin(), s.end()); }; |
74 | | |
75 | | template <typename T> |
76 | | concept absorbing_object = updatable_object<T> || appendable_object<T>; |
77 | | |
78 | | /** |
79 | | * This is a combination of the functions encode_string() and bytepad() defined |
80 | | * in NIST SP.800-185 Section 2.3. Additionally, the result is directly streamed |
81 | | * into the provided XOF to avoid unneccessary memory allocation or a byte vector. |
82 | | * |
83 | | * @param sink the XOF or byte vector to absorb the @p byte_strings into |
84 | | * @param padding_mod the modulus value to create a padding for (NIST calls this 'w') |
85 | | * @param byte_strings a variable-length list of byte strings to be encoded and |
86 | | * absorbed into the given @p xof |
87 | | * @returns the number of bytes absorbed into the @p xof |
88 | | */ |
89 | | template <absorbing_object T, typename... Ts> |
90 | | requires(concepts::constructible_from<std::span<const uint8_t>, Ts> && ...) |
91 | 0 | size_t keccak_absorb_padded_strings_encoding(T& sink, size_t padding_mod, Ts... byte_strings) { |
92 | 0 | BOTAN_ASSERT_NOMSG(padding_mod > 0); |
93 | | |
94 | | // used as temporary storage for all integer encodings in this function |
95 | 0 | std::array<uint8_t, keccak_max_int_encoding_size()> int_encoding_buffer; |
96 | | |
97 | | // absorbs byte strings and counts the number of absorbed bytes |
98 | 0 | size_t bytes_absorbed = 0; |
99 | 0 | auto absorb = [&](std::span<const uint8_t> bytes) { |
100 | 0 | if constexpr(updatable_object<T>) { |
101 | 0 | sink.update(bytes); |
102 | 0 | } else if constexpr(appendable_object<T>) { |
103 | 0 | sink.insert(sink.end(), bytes.begin(), bytes.end()); |
104 | 0 | } |
105 | 0 | bytes_absorbed += bytes.size(); |
106 | 0 | }; Unexecuted instantiation: Botan::keccak_absorb_padded_strings_encoding<std::__1::vector<unsigned char, Botan::secure_allocator<unsigned char> >, std::__1::span<unsigned char const, 18446744073709551615ul> >(std::__1::vector<unsigned char, Botan::secure_allocator<unsigned char> >&, unsigned long, std::__1::span<unsigned char const, 18446744073709551615ul>)::{lambda(std::__1::span<unsigned char const, 18446744073709551615ul>)#1}::operator()(std::__1::span<unsigned char const, 18446744073709551615ul>) const Unexecuted instantiation: Botan::keccak_absorb_padded_strings_encoding<Botan::cSHAKE_XOF, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >, std::__1::span<unsigned char const, 18446744073709551615ul> >(Botan::cSHAKE_XOF&, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >, std::__1::span<unsigned char const, 18446744073709551615ul>)::{lambda(std::__1::span<unsigned char const, 18446744073709551615ul>)#1}::operator()(std::__1::span<unsigned char const, 18446744073709551615ul>) const |
107 | | |
108 | | // encodes a given string and absorbs it into the XOF straight away |
109 | 0 | auto encode_string_and_absorb = [&](std::span<const uint8_t> bytes) { |
110 | 0 | absorb(keccak_int_left_encode(int_encoding_buffer, bytes.size() * 8)); |
111 | 0 | absorb(bytes); |
112 | 0 | }; Unexecuted instantiation: Botan::keccak_absorb_padded_strings_encoding<std::__1::vector<unsigned char, Botan::secure_allocator<unsigned char> >, std::__1::span<unsigned char const, 18446744073709551615ul> >(std::__1::vector<unsigned char, Botan::secure_allocator<unsigned char> >&, unsigned long, std::__1::span<unsigned char const, 18446744073709551615ul>)::{lambda(std::__1::span<unsigned char const, 18446744073709551615ul>)#2}::operator()(std::__1::span<unsigned char const, 18446744073709551615ul>) const Unexecuted instantiation: Botan::keccak_absorb_padded_strings_encoding<Botan::cSHAKE_XOF, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >, std::__1::span<unsigned char const, 18446744073709551615ul> >(Botan::cSHAKE_XOF&, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >, std::__1::span<unsigned char const, 18446744073709551615ul>)::{lambda(std::__1::span<unsigned char const, 18446744073709551615ul>)#2}::operator()(std::__1::span<unsigned char const, 18446744073709551615ul>) const |
113 | | |
114 | | // absorbs as many zero-bytes as requested into the XOF |
115 | 0 | auto absorb_padding = [&](size_t padding_bytes) { |
116 | 0 | for(size_t i = 0; i < padding_bytes; ++i) { |
117 | 0 | const uint8_t zero_byte = 0; |
118 | 0 | absorb({&zero_byte, 1}); |
119 | 0 | } |
120 | 0 | }; Unexecuted instantiation: Botan::keccak_absorb_padded_strings_encoding<std::__1::vector<unsigned char, Botan::secure_allocator<unsigned char> >, std::__1::span<unsigned char const, 18446744073709551615ul> >(std::__1::vector<unsigned char, Botan::secure_allocator<unsigned char> >&, unsigned long, std::__1::span<unsigned char const, 18446744073709551615ul>)::{lambda(unsigned long)#1}::operator()(unsigned long) const Unexecuted instantiation: Botan::keccak_absorb_padded_strings_encoding<Botan::cSHAKE_XOF, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >, std::__1::span<unsigned char const, 18446744073709551615ul> >(Botan::cSHAKE_XOF&, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >, std::__1::span<unsigned char const, 18446744073709551615ul>)::{lambda(unsigned long)#1}::operator()(unsigned long) const |
121 | | |
122 | | // implementation of bytepad(encode_string(Ts) || ...) that absorbs the result |
123 | | // staight into the given xof |
124 | 0 | absorb(keccak_int_left_encode(int_encoding_buffer, padding_mod)); |
125 | 0 | (encode_string_and_absorb(byte_strings), ...); |
126 | 0 | absorb_padding(padding_mod - (bytes_absorbed % padding_mod)); |
127 | |
|
128 | 0 | return bytes_absorbed; |
129 | 0 | } Unexecuted instantiation: unsigned long Botan::keccak_absorb_padded_strings_encoding<std::__1::vector<unsigned char, Botan::secure_allocator<unsigned char> >, std::__1::span<unsigned char const, 18446744073709551615ul> >(std::__1::vector<unsigned char, Botan::secure_allocator<unsigned char> >&, unsigned long, std::__1::span<unsigned char const, 18446744073709551615ul>) Unexecuted instantiation: unsigned long Botan::keccak_absorb_padded_strings_encoding<Botan::cSHAKE_XOF, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >, std::__1::span<unsigned char const, 18446744073709551615ul> >(Botan::cSHAKE_XOF&, unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >, std::__1::span<unsigned char const, 18446744073709551615ul>) |
130 | | |
131 | | } // namespace Botan |
132 | | |
133 | | #endif |