Source code
Revision control
Copy as Markdown
Other Tools
/*
* Permutation Ascon_p[rounds] as specified in NIST SP.800-232, Section 3
* (C) 2025 Jack Lloyd
* 2025 René Meusel
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/internal/ascon_perm.h>
#include <botan/internal/buffer_stuffer.h>
#include <botan/internal/rotate.h>
#include <botan/internal/sponge_processing.h>
namespace Botan {
void Ascon_p::absorb(std::span<const uint8_t> input, std::optional<uint8_t> permutation_rounds) {
const auto rounds = permutation_rounds.value_or(m_processing_rounds);
absorb_into_sponge(*this, input, [this, rounds] { permute(rounds); });
}
void Ascon_p::squeeze(std::span<uint8_t> output) {
squeeze_from_sponge(*this, output);
}
void Ascon_p::percolate_in(std::span<uint8_t> data) {
BufferSlicer input_slicer(data);
BufferStuffer output_stuffer(data);
process_bytes_in_sponge(*this, data.size(), [&](uint64_t state_word, auto bounds) {
state_word ^= bounds.read_from(input_slicer);
bounds.write_into(output_stuffer, state_word);
return state_word;
});
BOTAN_ASSERT_NOMSG(input_slicer.empty());
BOTAN_ASSERT_NOMSG(output_stuffer.full());
}
void Ascon_p::percolate_out(std::span<uint8_t> data) {
BufferSlicer input_slicer(data);
BufferStuffer output_stuffer(data);
process_bytes_in_sponge(*this, data.size(), [&](uint64_t state_word, auto bounds) {
const auto input_word = bounds.read_from(input_slicer);
bounds.write_into(output_stuffer, state_word ^ input_word);
return bounds.masked_assignment(state_word, input_word);
});
BOTAN_ASSERT_NOMSG(input_slicer.empty());
BOTAN_ASSERT_NOMSG(output_stuffer.full());
}
void Ascon_p::finish(uint8_t rounds) {
// NIST SP.800-232, Section 2.1 (Algorithm 2 "pad()")
// The padding is defined as:
// 1. The first padding bit is set to 1
// 2. The remaining bits are set to 0
constexpr std::array<uint8_t, state_bytes()> padding{0x01};
// We must always add a padded final input block, if the last verbatim
// input block aligned with the byte rate, the final block may be just
// padding bytes, otherwise the final block is padded as needed.
absorb(std::span{padding}.first(byte_rate() - cursor()), rounds);
BOTAN_ASSERT_NOMSG(cursor() == 0);
}
void Ascon_p::permute(uint8_t rounds) {
BOTAN_DEBUG_ASSERT(rounds <= 16);
auto& S = state();
// NIST SP.800-232, Table 5
constexpr std::array<uint64_t, 16> round_constants = {
0x3c, 0x2d, 0x1e, 0x0f, 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87, 0x78, 0x69, 0x5a, 0x4b};
for(uint8_t i = 0; i < rounds; ++i) {
// Constant addition layer p_C
// NIST SP.800-232, Section 3.2
S[2] ^= round_constants[16 - rounds + i];
// Substitution layer p_S
// NIST SP.800-232, Section 3.3, most notably Figure 3
S[0] ^= S[4];
S[4] ^= S[3];
S[2] ^= S[1];
auto tmp = S;
tmp[0] = ~tmp[0] & S[1];
tmp[1] = ~tmp[1] & S[2];
tmp[2] = ~tmp[2] & S[3];
tmp[3] = ~tmp[3] & S[4];
tmp[4] = ~tmp[4] & S[0];
S[0] ^= tmp[1];
S[1] ^= tmp[2];
S[2] ^= tmp[3];
S[3] ^= tmp[4];
S[4] ^= tmp[0];
S[1] ^= S[0];
S[0] ^= S[4];
S[3] ^= S[2];
S[2] = ~S[2];
// Linear diffusion layer p_L
// NIST SP.800-232, Section 3.4
S[0] = S[0] ^ rotr<19>(S[0]) ^ rotr<28>(S[0]);
S[1] = S[1] ^ rotr<61>(S[1]) ^ rotr<39>(S[1]);
S[2] = S[2] ^ rotr<1>(S[2]) ^ rotr<6>(S[2]);
S[3] = S[3] ^ rotr<10>(S[3]) ^ rotr<17>(S[3]);
S[4] = S[4] ^ rotr<7>(S[4]) ^ rotr<41>(S[4]);
}
}
} // namespace Botan