libdpf/include/dpf/prg_lowmc.hpp

162 lines
4.6 KiB
C++
Raw Permalink Normal View History

/// @file dpf/prg_lowmc.hpp
/// @brief Fixed-key LowMC PRG. Same Matyas–Meyer–Oseas stretch as `aes128`.
/// @copyright Copyright (c) 2019-2026 Ryan Henry and [others](@ref authors)
/// @license Released under a GNU General Public v2.0 (GPLv2) license;
/// see [LICENSE.md](@ref license) for details.
#ifndef LIBDPF_INCLUDE_DPF_PRG_LOWMC_HPP__
#define LIBDPF_INCLUDE_DPF_PRG_LOWMC_HPP__
#include <array>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <stdexcept>
#include "hedley/hedley.h"
#include "simde/simde/x86/avx2.h"
#include "portable-snippets/exact-int/exact-int.h"
#include "lowmc/LowMC.h"
#include "lowmc/LowMC.cpp"
#include "dpf/prg_count.hpp"
namespace dpf
{
namespace prg
{
/// @brief LowMCv3, 128-bit block and key, 10 S-boxes, 32 rounds, all-zero key.
/// @details `eval(seed, pos)` is `E(seed ⊕ pos) ⊕ seed`, with `pos` in the low lane.
struct lowmc128 final
{
using block_type = simde__m128i;
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
static block_type eval(block_type seed, psnip_uint32_t pos) noexcept
{
note_eval(1, primitive::lowmc);
block_type in = simde_mm_xor_si128(seed, simde_mm_set_epi64x(0, pos));
return simde_mm_xor_si128(permute(in), seed);
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
static auto eval01(block_type seed) noexcept
{
HEDLEY_PRAGMA(GCC diagnostic push)
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
return std::array<block_type, 2>{eval(seed, 0), eval(seed, 1)};
HEDLEY_PRAGMA(GCC diagnostic pop)
}
HEDLEY_ALWAYS_INLINE
static void eval(block_type seed, block_type * HEDLEY_RESTRICT output,
psnip_uint32_t count, psnip_uint32_t pos = 0)
{
if (count > 1 &&
pos > static_cast<psnip_uint32_t>(~static_cast<psnip_uint32_t>(0)) - (count - 1u))
{
throw std::invalid_argument("prg lane index is out of range");
}
for (psnip_uint32_t i = 0; i < count; ++i)
{
output[i] = eval(seed, pos + i);
}
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
HEDLEY_NON_NULL(1, 2, 3)
static void eval01_x4(const block_type * HEDLEY_RESTRICT seeds,
block_type * HEDLEY_RESTRICT left,
block_type * HEDLEY_RESTRICT right) noexcept
{
for (std::size_t i = 0; i < 4; ++i)
{
auto kids = eval01(seeds[i]);
left[i] = kids[0];
right[i] = kids[1];
}
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
HEDLEY_NON_NULL(1, 2)
static void eval_x4(const block_type * HEDLEY_RESTRICT seeds,
block_type * HEDLEY_RESTRICT output, psnip_uint32_t pos = 0) noexcept
{
for (std::size_t i = 0; i < 4; ++i)
{
output[i] = eval(seeds[i], pos);
}
}
HEDLEY_NO_THROW
HEDLEY_ALWAYS_INLINE
HEDLEY_NON_NULL(1, 2)
static void eval_x8(const block_type * HEDLEY_RESTRICT seeds,
block_type * HEDLEY_RESTRICT output, psnip_uint32_t pos = 0) noexcept
{
for (std::size_t i = 0; i < 8; ++i)
{
output[i] = eval(seeds[i], pos);
}
}
/// @brief Raw-bit subtractive share of `T` for party `Party` (see `prg.hpp`).
/// @tparam T value type
/// @tparam Party party index, `0` or `1`
/// @param seed the PRG seed
/// @param pos the 0-based index
/// @return Raw-bit subtractive share of `T` for party `Party` (see `prg.hpp`)
/// @see `prg.hpp`
template <typename T, std::size_t Party>
HEDLEY_NO_THROW
static auto expand(block_type seed, psnip_uint32_t pos = 0) noexcept;
private:
HEDLEY_NO_THROW
static lowmc::block to_block(block_type x) noexcept
{
std::uint64_t lane[2];
std::memcpy(lane, &x, sizeof(lane));
lowmc::block b;
for (unsigned i = 0; i < 64; ++i)
{
b[i] = (lane[0] >> i) & 1ull;
b[i + 64] = (lane[1] >> i) & 1ull;
}
return b;
}
HEDLEY_NO_THROW
static block_type from_block(const lowmc::block & b) noexcept
{
std::uint64_t lane[2] = {0, 0};
for (unsigned i = 0; i < 64; ++i)
{
lane[0] |= static_cast<std::uint64_t>(b[i]) << i;
lane[1] |= static_cast<std::uint64_t>(b[i + 64]) << i;
}
block_type x;
std::memcpy(&x, lane, sizeof(x));
return x;
}
HEDLEY_NO_THROW
static block_type permute(block_type x) noexcept
{
static lowmc::LowMC cipher;
return from_block(cipher.encrypt(to_block(x)));
}
}; // struct lowmc128
} // namespace prg
} // namespace dpf
#endif // LIBDPF_INCLUDE_DPF_PRG_LOWMC_HPP__