2026-09-24 14:08:32 -06:00
|
|
|
|
/// @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>
|
2026-09-24 20:44:07 -06:00
|
|
|
|
#include <stdexcept>
|
2026-09-24 14:08:32 -06:00
|
|
|
|
|
|
|
|
|
|
#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
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
/// LowMCv3, 128-bit block and key, 10 S-boxes, 32 rounds, all-zero key.
|
|
|
|
|
|
/// `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,
|
2026-09-24 20:44:07 -06:00
|
|
|
|
psnip_uint32_t count, psnip_uint32_t pos = 0)
|
2026-09-24 14:08:32 -06:00
|
|
|
|
{
|
2026-09-24 20:44:07 -06:00
|
|
|
|
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");
|
|
|
|
|
|
}
|
2026-09-24 14:08:32 -06:00
|
|
|
|
for (psnip_uint32_t i = 0; i < count; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
output[i] = eval(seed, pos + i);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HEDLEY_NO_THROW
|
|
|
|
|
|
HEDLEY_ALWAYS_INLINE
|
2026-09-24 20:44:07 -06:00
|
|
|
|
HEDLEY_NON_NULL(1, 2, 3)
|
2026-09-24 14:08:32 -06:00
|
|
|
|
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
|
2026-09-24 20:44:07 -06:00
|
|
|
|
HEDLEY_NON_NULL(1, 2)
|
2026-09-24 14:08:32 -06:00
|
|
|
|
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
|
2026-09-24 20:44:07 -06:00
|
|
|
|
HEDLEY_NON_NULL(1, 2)
|
2026-09-24 14:08:32 -06:00
|
|
|
|
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);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Raw-bit subtractive share of `T` for party `Party` (see `prg.hpp`).
|
|
|
|
|
|
template <typename T, std::size_t Party>
|
2026-09-24 20:44:07 -06:00
|
|
|
|
HEDLEY_NO_THROW
|
2026-09-24 14:08:32 -06:00
|
|
|
|
static auto expand(block_type seed, psnip_uint32_t pos = 0) noexcept;
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
2026-09-24 20:44:07 -06:00
|
|
|
|
HEDLEY_NO_THROW
|
2026-09-24 14:08:32 -06:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-24 20:44:07 -06:00
|
|
|
|
HEDLEY_NO_THROW
|
2026-09-24 14:08:32 -06:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-24 20:44:07 -06:00
|
|
|
|
HEDLEY_NO_THROW
|
2026-09-24 14:08:32 -06:00
|
|
|
|
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__
|