Botan 3.4.0
Crypto and TLS for C&
keccak_helpers.h
Go to the documentation of this file.
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 <botan/assert.h>
13
14#include <array>
15#include <concepts>
16#include <cstdint>
17#include <span>
18
19namespace 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 */
36BOTAN_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 */
53BOTAN_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 */
60
61/**
62 * @returns the maximum required bytes for encodings of keccak_int_left_encode() or
63 * keccak_int_right_encode()
64 */
65constexpr size_t keccak_max_int_encoding_size() {
66 return sizeof(size_t) + 1 /* the length tag */;
67}
68
69template <typename T>
70concept updatable_object = requires(T& a, std::span<const uint8_t> span) { a.update(span); };
71
72template <typename T>
73concept appendable_object = requires(T& a, std::span<const uint8_t> s) { a.insert(a.end(), s.begin(), s.end()); };
74
75template <typename 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 */
89template <absorbing_object T, typename... Ts>
90 requires(std::constructible_from<std::span<const uint8_t>, Ts> && ...)
91size_t keccak_absorb_padded_strings_encoding(T& sink, size_t padding_mod, Ts... byte_strings) {
92 BOTAN_ASSERT_NOMSG(padding_mod > 0);
93
94 // used as temporary storage for all integer encodings in this function
95 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 size_t bytes_absorbed = 0;
99 auto absorb = [&](std::span<const uint8_t> bytes) {
100 if constexpr(updatable_object<T>) {
101 sink.update(bytes);
102 } else if constexpr(appendable_object<T>) {
103 sink.insert(sink.end(), bytes.begin(), bytes.end());
104 }
105 bytes_absorbed += bytes.size();
106 };
107
108 // encodes a given string and absorbs it into the XOF straight away
109 auto encode_string_and_absorb = [&](std::span<const uint8_t> bytes) {
110 absorb(keccak_int_left_encode(int_encoding_buffer, bytes.size() * 8));
111 absorb(bytes);
112 };
113
114 // absorbs as many zero-bytes as requested into the XOF
115 auto absorb_padding = [&](size_t padding_bytes) {
116 for(size_t i = 0; i < padding_bytes; ++i) {
117 const uint8_t zero_byte = 0;
118 absorb({&zero_byte, 1});
119 }
120 };
121
122 // implementation of bytepad(encode_string(Ts) || ...) that absorbs the result
123 // staight into the given xof
124 absorb(keccak_int_left_encode(int_encoding_buffer, padding_mod));
125 (encode_string_and_absorb(byte_strings), ...);
126 absorb_padding(padding_mod - (bytes_absorbed % padding_mod));
127
128 return bytes_absorbed;
129}
130
131} // namespace Botan
132
133#endif
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
#define BOTAN_TEST_API
Definition compiler.h:51
FE_25519 T
Definition ge.cpp:34
std::span< const uint8_t > keccak_int_left_encode(std::span< uint8_t > out, size_t x)
size_t keccak_absorb_padded_strings_encoding(T &sink, size_t padding_mod, Ts... byte_strings)
std::span< const uint8_t > keccak_int_right_encode(std::span< uint8_t > out, size_t x)
constexpr size_t keccak_max_int_encoding_size()
size_t keccak_int_encoding_size(size_t x)