libdpf/test/tests/dpf_key_test.cpp
Ryan Henry e4e666f459 Initial import of libdpf.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 14:08:32 -06:00

208 lines
9.3 KiB
C++

#include <gtest/gtest.h>
#include "dpf.hpp"
simde__m128i fake_root_sampler()
{
static int64_t ret_int = 0x4;
simde__m128i ret = {ret_int, 0};
ret_int <<= 1;
return ret;
}
TEST(DpfKeyTest, HardCodedGenCheck)
{
using input_type = uint8_t;
using output_type = uint32_t;
input_type x = 0xAA; // = 0b 1010 1010
output_type y0 = 0xAAAAAAAA; // additive / subtractive share
dpf::xor_wrapper<output_type> y1 = dpf::xor_wrapper<output_type>(0x55555555); // xor share
dpf::wildcard_value<output_type> y2 = dpf::wildcard_value<output_type>(); // wildcard
auto [dpf0, dpf1] = dpf::make_dpf<dpf::prg::aes128, dpf::prg::aes128, &fake_root_sampler>(x, y0, y1, y2);
// 128-bit representation of 0x4 with lowest bit unset
ASSERT_EQ(dpf0.root()[1], 0);
ASSERT_EQ(dpf0.root()[0], 0x4);
// 128-bit representation of 0x8 with lowest bit set
ASSERT_EQ(dpf1.root()[1], 0);
ASSERT_EQ(dpf1.root()[0], 0x9);
ASSERT_EQ(dpf0.correction_words()[0][1], 0x7ff85a65ce2111c9);
ASSERT_EQ(dpf0.correction_words()[0][0], 0x36863b84ab3944d2);
ASSERT_EQ(dpf0.correction_words()[0][1], dpf1.correction_words()[0][1]);
ASSERT_EQ(dpf0.correction_words()[0][0], dpf1.correction_words()[0][0]);
ASSERT_EQ(dpf0.correction_advice()[0], 0b00);
ASSERT_EQ(dpf0.correction_advice()[0], dpf1.correction_advice()[0]);
// dpf0 after level 0:
// 0xc4c4bd72d02958c541201f063e3c1173
// dpf1 after level 0:
// 0xdd09c23385ba379378631a3a9c46f52e
ASSERT_EQ(dpf0.correction_words()[1][1], 0x9ca0f55370cf6bfe);
ASSERT_EQ(dpf0.correction_words()[1][0], 0xc3b9e951c500d272);
ASSERT_EQ(dpf0.correction_words()[1][1], dpf1.correction_words()[1][1]);
ASSERT_EQ(dpf0.correction_words()[1][0], dpf1.correction_words()[1][0]);
ASSERT_EQ(dpf0.correction_advice()[1], 0b01);
ASSERT_EQ(dpf0.correction_advice()[1], dpf1.correction_advice()[1]);
// dpf0 after level 1:
// 0x2bef771157872382accfcf2a5e2f7e57
// dpf1 after level 1:
// 0x7604b860b26e8586b0c6ad05ec6886ce
ASSERT_EQ(dpf0.correction_words()[2][1], 0x886f1eb652b72eda);
ASSERT_EQ(dpf0.correction_words()[2][0], 0x0ff98303eca43ab6);
ASSERT_EQ(dpf0.correction_words()[2][1], dpf1.correction_words()[2][1]);
ASSERT_EQ(dpf0.correction_words()[2][0], dpf1.correction_words()[2][0]);
ASSERT_EQ(dpf0.correction_advice()[2], 0b10);
ASSERT_EQ(dpf0.correction_advice()[2], dpf1.correction_advice()[2]);
// dpf0 after level 2:
// 0x39adfa95d94a10fdff65a956019f0a6c
// dpf1 after level 2:
// 0x59be9dba7aa04f9a12d23cd995d90135
ASSERT_EQ(dpf0.correction_words()[3][1], 0x4e69100f5b844cb9);
ASSERT_EQ(dpf0.correction_words()[3][0], 0x9ac5b5baba9a193b);
ASSERT_EQ(dpf0.correction_words()[3][1], dpf1.correction_words()[3][1]);
ASSERT_EQ(dpf0.correction_words()[3][0], dpf1.correction_words()[3][0]);
ASSERT_EQ(dpf0.correction_advice()[3], 0b10);
ASSERT_EQ(dpf0.correction_advice()[3], dpf1.correction_advice()[3]);
// dpf0 after level 3:
// 0x028922e3e5fca1a824a12136fc2ed7e3
// dpf1 after level 3:
// 0xd7699bb72bb9e8d42363e899692ecf36
ASSERT_EQ(dpf0.correction_words()[4][1], 0xe701887629e08652);
ASSERT_EQ(dpf0.correction_words()[4][0], 0xbd92c2853e1e2457);
ASSERT_EQ(dpf0.correction_words()[4][1], dpf1.correction_words()[4][1]);
ASSERT_EQ(dpf0.correction_words()[4][0], dpf1.correction_words()[4][0]);
ASSERT_EQ(dpf0.correction_advice()[4], 0b01);
ASSERT_EQ(dpf0.correction_advice()[4], dpf1.correction_advice()[4]);
// dpf0 after level 4:
// 0xe0deacc7c5f61d83aebacde0bd97f61f
// dpf1 after level 4:
// 0x96be3cfb09b9bc84e0a6de756d9589f2
ASSERT_EQ(dpf0.correction_words()[5][1], 0xc8edc84047a7b3df);
ASSERT_EQ(dpf0.correction_words()[5][0], 0xbc0d1f614b01d608);
ASSERT_EQ(dpf0.correction_words()[5][1], dpf1.correction_words()[5][1]);
ASSERT_EQ(dpf0.correction_words()[5][0], dpf1.correction_words()[5][0]);
ASSERT_EQ(dpf0.correction_advice()[5], 0b01);
ASSERT_EQ(dpf0.correction_advice()[5], dpf1.correction_advice()[5]);
// dpf0 after level 5:
// 0x3cb3c5060d58e866c703b4b7939725b8
// dpf1 after level 5:
// 0x1afcd5c2a2a3f4b9be5b9564585df4f3
// Leaf layer
// dpf0 make leaf mask inner:
// 0: bb994bbd eba3cbb2 39b39032 e5f31930
// 1: d32db0c1 3da76455 961fadd7 4b5d7350
// 2: 5de4be73 fd14043f 19b22bba be0ff8f8
// dpf1 make leaf mask inner:
// 0: 921bb1c5 b0a6c8c2 484ae275 9a752740
// 1: 279a2459 0d9d913f f1bf8700 fc603f6a
// 2: cb839afd 6a68b9cf b0c6aac6 7dd6f9ad
// naked masks:
// 0: 00000000 aaaaaaaa 00000000 00000000
// 1: 00000000 55555555 00000000 00000000
// 2: 00000000 00000000 00000000 00000000
// correction words:
// 0: d6826608 1a585266 0e975243 b4820e10
// 1: 546c7398 7aa0d795 5b9fd929 b102cc1a
// 2: 6d9edc8a 6d54b590 97147f0c bfc700b5
ASSERT_EQ(dpf0.leaf<0>()[1], 0xd68266081a585266);
ASSERT_EQ(dpf0.leaf<0>()[0], 0x0e975243b4820e10);
ASSERT_EQ(dpf0.leaf<0>()[1], dpf1.leaf<0>()[1]);
ASSERT_EQ(dpf0.leaf<0>()[0], dpf1.leaf<0>()[0]);
ASSERT_EQ(dpf0.leaf<1>()[1], 0xf4b79498656fa03f);
ASSERT_EQ(dpf0.leaf<1>()[0], 0x67a02ad7b73d4c3a);
ASSERT_EQ(dpf0.leaf<1>()[1], dpf1.leaf<1>()[1]);
ASSERT_EQ(dpf0.leaf<1>()[0], dpf1.leaf<1>()[0]);
// vector:
// [0|0|1|0] which corresponds to input x
// lsb of "dpf0 after leaf 5" is 0 (used as sign bit)
// => output_type(2*sign-1) = output_type(2*0-1) = 0xFFFFFFFF
simde__m128i vector{0x0000000000000000, 0x00000000FFFFFFFF},
blinded0 = simde_mm_add_epi32(vector, dpf1.beaver<2>().vector_blind),
blinded1 = simde_mm_add_epi32(vector, dpf0.beaver<2>().vector_blind),
mulleaf0 = simde_mm_mullo_epi32(dpf0.beaver<2>().vector_blind, simde_mm_set1_epi32(dpf1.beaver<2>().output_blind)),
mulleaf1 = simde_mm_mullo_epi32(dpf1.beaver<2>().vector_blind, simde_mm_set1_epi32(dpf0.beaver<2>().output_blind)),
leaf = simde_mm_sub_epi32(simde_mm_add_epi32(dpf0.leaf<2>(), dpf1.leaf<2>()),
simde_mm_add_epi32(mulleaf0, mulleaf1));
ASSERT_EQ(blinded0[1], dpf0.beaver<2>().blinded_vector[1]);
ASSERT_EQ(blinded0[0], dpf0.beaver<2>().blinded_vector[0]);
ASSERT_EQ(blinded1[1], dpf1.beaver<2>().blinded_vector[1]);
ASSERT_EQ(blinded1[0], dpf1.beaver<2>().blinded_vector[0]);
ASSERT_EQ(leaf[1], 0x6d9edc8a6d54b590);
ASSERT_EQ(leaf[0], 0x97147f0cbfc700b5);
ASSERT_EQ(dpf0.is_wildcard(0), false);
ASSERT_EQ(dpf0.is_wildcard(1), false);
ASSERT_EQ(dpf0.is_wildcard(2), true);
ASSERT_EQ(dpf1.is_wildcard(0), false);
ASSERT_EQ(dpf1.is_wildcard(1), false);
ASSERT_EQ(dpf1.is_wildcard(2), true);
}
TEST(DpfKeyTest, MakeDpfRandomPoint)
{
using prg_type = dpf::prg::aes128;
using input_type = uint8_t;
using output_type = uint32_t;
using output_type0 = std::make_signed_t<output_type>;
using output_type1 = std::make_unsigned_t<output_type>;
using output_type2 = dpf::xor_wrapper<output_type>;
using dpf_type = dpf::utils::dpf_type_t<prg_type, prg_type, input_type, output_type0, output_type1, output_type2>;
static constexpr auto from_integral_type = dpf::utils::make_from_integral_value<input_type>{};
static constexpr auto from_integral_type_output0 = dpf::utils::make_from_integral_value<output_type0>{};
static constexpr auto from_integral_type_output1 = dpf::utils::make_from_integral_value<output_type1>{};
static constexpr auto from_integral_type_output2 = dpf::utils::make_from_integral_value<output_type2>{};
output_type0 zero_output0 = from_integral_type_output0(0),
one_output0 = from_integral_type_output0(1);
output_type1 zero_output1 = from_integral_type_output1(0),
one_output1 = from_integral_type_output1(1);
output_type2 zero_output2 = from_integral_type_output2(0),
one_output2 = from_integral_type_output2(1);
auto [dpf0, dpf1, x0, x1] = dpf::make_dpf_random_point<dpf_type>();
input_type x = x0 + x1;
auto [buf0, iter0] = dpf::eval_full<0, 1, 2>(dpf0);
auto [buf1, iter1] = dpf::eval_full<0, 1, 2>(dpf1);
auto zip0 = dpf::tuple_as_zip(iter0);
auto zip1 = dpf::tuple_as_zip(iter1);
auto it0 = std::cbegin(zip0);
auto it1 = std::cbegin(zip1);
input_type cur = from_integral_type(0);
for (std::size_t i = 0; i < 1ul << dpf::utils::bitlength_of_v<input_type>; ++i, ++cur, ++it0, ++it1)
{
if (cur == x)
{
ASSERT_EQ(static_cast<output_type0>(dpf::reconstruct(std::get<0>(*it0), std::get<0>(*it1))), one_output0);
ASSERT_EQ(static_cast<output_type1>(dpf::reconstruct(std::get<1>(*it0), std::get<1>(*it1))), one_output1);
ASSERT_EQ(static_cast<output_type2>(dpf::reconstruct(std::get<2>(*it0), std::get<2>(*it1))), one_output2);
}
else
{
ASSERT_EQ(static_cast<output_type0>(dpf::reconstruct(std::get<0>(*it0), std::get<0>(*it1))), zero_output0);
ASSERT_EQ(static_cast<output_type1>(dpf::reconstruct(std::get<1>(*it0), std::get<1>(*it1))), zero_output1);
ASSERT_EQ(static_cast<output_type2>(dpf::reconstruct(std::get<2>(*it0), std::get<2>(*it1))), zero_output2);
}
}
ASSERT_EQ(it0, std::end(zip0));
ASSERT_EQ(it1, std::end(zip1));
}