/* * 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 #include #include #include namespace Botan { void Ascon_p::absorb(std::span input, std::optional 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 output) { squeeze_from_sponge(*this, output); } void Ascon_p::percolate_in(std::span 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 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 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 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