libdpf/include/dpf/prg_lowmc.hpp

159 lines
4.5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/// @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"
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
{
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__