fix: bug regarding polynomial evaluations view in CUDA backend (#506)

fixing:
(1) not building polynomials and tests for grumpkin curve (no NTT)
(2) polynomial API C++ example compilation and (when compilation is
fixed) memory corruption
(3) bug fix in poly CUDA backend regarding transformation to evaluations
in some cases
This commit is contained in:
yshekel
2024-05-08 21:02:18 +03:00
committed by GitHub
parent 732ee51552
commit 2905d2a469
5 changed files with 54 additions and 51 deletions

View File

@@ -133,7 +133,7 @@ void example_multiplication(const int log0, const int log1)
std::cout << "multiply and evaluate: " << mx << std::endl; std::cout << "multiply and evaluate: " << mx << std::endl;
} }
void example_multiplicationScalar(const int log0) void example_multiplication_scalar(const int log0)
{ {
std::cout << std::endl << "Example: Scalar by Polynomial multiplication" << std::endl; std::cout << std::endl << "Example: Scalar by Polynomial multiplication" << std::endl;
const int size = 1 << log0; const int size = 1 << log0;
@@ -163,7 +163,7 @@ void example_monomials()
std::cout << "Expected f'(x) = " << expected_addmonmon_f_x << std::endl; std::cout << "Expected f'(x) = " << expected_addmonmon_f_x << std::endl;
} }
void example_ReadCoeffsToHost() void example_read_coeffs_to_host()
{ {
std::cout << std::endl << "Example: Read coefficients to host" << std::endl; std::cout << std::endl << "Example: Read coefficients to host" << std::endl;
const scalar_t coeffs_f[3] = {zero, one, two}; // 0+1x+2x^2 const scalar_t coeffs_f[3] = {zero, one, two}; // 0+1x+2x^2
@@ -190,7 +190,7 @@ void example_ReadCoeffsToHost()
} }
} }
void example_divisionSmall() void example_division_small()
{ {
std::cout << std::endl << "Example: Polynomial division (small)" << std::endl; std::cout << std::endl << "Example: Polynomial division (small)" << std::endl;
const scalar_t coeffs_a[4] = {five, zero, four, three}; // 3x^3+4x^2+5 const scalar_t coeffs_a[4] = {five, zero, four, three}; // 3x^3+4x^2+5
@@ -208,7 +208,7 @@ void example_divisionSmall()
std::cout << "Reminder: 1:" << r_coeffs[1] << " expected: " << scalar_t::from(3) << std::endl; std::cout << "Reminder: 1:" << r_coeffs[1] << " expected: " << scalar_t::from(3) << std::endl;
} }
void example_divisionLarge(const int log0, const int log1) void example_division_large(const int log0, const int log1)
{ {
std::cout << std::endl << "Example: Polynomial division (large)" << std::endl; std::cout << std::endl << "Example: Polynomial division (large)" << std::endl;
const int size0 = 1 << log0, size1 = 1 << log1; const int size0 = 1 << log0, size1 = 1 << log1;
@@ -226,7 +226,7 @@ void example_divisionLarge(const int log0, const int log1)
std::cout << "rhs = " << bx * qx + rx << std::endl; std::cout << "rhs = " << bx * qx + rx << std::endl;
} }
void example_divideByVanishingPolynomial() void example_divide_by_vanishing_polynomial()
{ {
std::cout << std::endl << "Example: Polynomial division by vanishing polynomial" << std::endl; std::cout << std::endl << "Example: Polynomial division by vanishing polynomial" << std::endl;
const scalar_t coeffs_v[5] = {minus_one, zero, zero, zero, one}; // x^4-1 vanishes on 4th roots of unity const scalar_t coeffs_v[5] = {minus_one, zero, zero, zero, one}; // x^4-1 vanishes on 4th roots of unity
@@ -254,7 +254,8 @@ void example_clone(const int log0)
std::cout << "h(x) = " << h(x) << " expected: " << g(x) << std::endl; std::cout << "h(x) = " << h(x) << " expected: " << g(x) << std::endl;
} }
void example_EvenOdd() { void example_even_odd()
{
std::cout << std::endl << "Example: Split into even and odd powers " << std::endl; std::cout << std::endl << "Example: Split into even and odd powers " << std::endl;
const scalar_t coeffs[4] = {one, two, three, four}; // 1+2x+3x^2+4x^3 const scalar_t coeffs[4] = {one, two, three, four}; // 1+2x+3x^2+4x^3
auto f = Polynomial_t::from_coefficients(coeffs, 4); auto f = Polynomial_t::from_coefficients(coeffs, 4);
@@ -270,36 +271,31 @@ void example_EvenOdd() {
std::cout << "Odd: 1:" << odd_coeffs[1] << " expected: " << four << std::endl; std::cout << "Odd: 1:" << odd_coeffs[1] << " expected: " << four << std::endl;
} }
void example_Slice() { void example_slice()
{
std::cout << std::endl << "Example: Slice polynomial " << std::endl; std::cout << std::endl << "Example: Slice polynomial " << std::endl;
const scalar_t coeffs[4] = {one, two, three, four}; // 1+2x+3x^2+4x^3 const scalar_t coeffs[4] = {one, two, three, four}; // 1+2x+3x^2+4x^3
auto f = Polynomial_t::from_coefficients(coeffs, 4); auto f = Polynomial_t::from_coefficients(coeffs, 4);
auto f_slice = f.slice(0/=offset/, 3/=stride/, 2*/=size/); // 1+4x auto f_slice = f.slice(0 /*=offset*/, 3 /*= stride*/, 2 /*/= size*/); // 1+4x
scalar_t slice_coeffs[2] = {0}; scalar_t slice_coeffs[2] = {0};
const auto slice_nof_coeffs = f_slice.copy_coeffs(slice_coeffs, 0, 1); const auto slice_nof_coeffs = f_slice.copy_coeffs(slice_coeffs, 0, 1);
std::cout << "Slice: 0:" << slice_coeffs[0] << " expected: " << one << std::endl; std::cout << "Slice: 0:" << slice_coeffs[0] << " expected: " << one << std::endl;
std::cout << "Slice: 1:" << slice_coeffs[1] << " expected: " << four << std::endl; std::cout << "Slice: 1:" << slice_coeffs[1] << " expected: " << four << std::endl;
} }
void example_DeviceMemoryView() { void example_device_memory_view()
{
const int log_size = 6; const int log_size = 6;
const int size = 1 << log_size; const int size = 1 << log_size;
auto f = randomize_polynomial(size); auto f = randomize_polynomial(size);
auto [d_coeff, N, device_id] = f.get_coefficients_view(); auto [d_coeffs, N, device_id] = f.get_coefficients_view();
// commit coefficients to Merkle tree
device_context::DeviceContext ctx = device_context::get_default_device_context(); // compute coset evaluations
PoseidonConstants<scalar_t> constants; auto coset_evals = std::make_unique<scalar_t[]>(size);
init_optimized_poseidon_constants<scalar_t>(2, ctx, &constants); auto ntt_config = ntt::default_ntt_config<scalar_t>();
uint32_t tree_height = log_size + 1; ntt_config.are_inputs_on_device = true; // using the device data directly as a view
int keep_rows = 0; // keep all rows ntt_config.coset_gen = ntt::get_root_of_unity<scalar_t>(size * 2);
size_t digests_len = log_size - 1; ntt::ntt(d_coeffs.get(), size, ntt::NTTDir::kForward, ntt_config, coset_evals.get());
scalar_t* digests = static_cast<scalar_t*>(malloc(sizeof(scalar_t) * digests_len));
TreeBuilderConfig config = default_merkle_config();
config.keep_rows = keep_rows;
config.are_inputs_on_device = true;
build_merkle_tree<scalar_t, (2+1)>(d_coeff.get(), digests, tree_height, constants, config);
std::cout << "Merkle tree root: " << digests[0] << std::endl;
free(digests);
} }
int main(int argc, char** argv) int main(int argc, char** argv)
@@ -319,15 +315,15 @@ int main(int argc, char** argv)
example_addition(12, 17); example_addition(12, 17);
example_addition_inplace(2, 2); example_addition_inplace(2, 2);
example_multiplication(15, 12); example_multiplication(15, 12);
example_multiplicationScalar(15); example_multiplication_scalar(15);
example_monomials(); example_monomials();
example_ReadCoeffsToHost(); example_read_coeffs_to_host();
example_divisionSmall(); example_division_small();
example_divisionLarge(12, 2); example_division_large(12, 2);
example_divideByVanishingPolynomial(); example_divide_by_vanishing_polynomial();
example_EvenOdd(); example_even_odd();
example_Slice(); example_slice();
example_DeviceMemoryView(); example_device_memory_view();
return 0; return 0;
} }

View File

@@ -21,8 +21,6 @@ set(POLYNOMIAL_SOURCE_FILES
${SRC}/polynomials/cuda_backend/polynomial_cuda_backend.cu ${SRC}/polynomials/cuda_backend/polynomial_cuda_backend.cu
${SRC}/polynomials/polynomials_c_api.cu) ${SRC}/polynomials/polynomials_c_api.cu)
list(APPEND FIELD_SOURCE ${POLYNOMIAL_SOURCE_FILES})
# TODO: impl poseidon for small fields. note that it needs to be defined over the extension field! # TODO: impl poseidon for small fields. note that it needs to be defined over the extension field!
if (DEFINED CURVE) if (DEFINED CURVE)
list(APPEND FIELD_SOURCE ${SRC}/poseidon/poseidon.cu) list(APPEND FIELD_SOURCE ${SRC}/poseidon/poseidon.cu)
@@ -32,6 +30,7 @@ endif()
if (NOT FIELD IN_LIST SUPPORTED_FIELDS_WITHOUT_NTT) if (NOT FIELD IN_LIST SUPPORTED_FIELDS_WITHOUT_NTT)
list(APPEND FIELD_SOURCE ${SRC}/ntt/extern.cu) list(APPEND FIELD_SOURCE ${SRC}/ntt/extern.cu)
list(APPEND FIELD_SOURCE ${SRC}/ntt/kernel_ntt.cu) list(APPEND FIELD_SOURCE ${SRC}/ntt/kernel_ntt.cu)
list(APPEND FIELD_SOURCE ${POLYNOMIAL_SOURCE_FILES}) # requires NTT
endif() endif()
add_library(${TARGET} STATIC ${FIELD_SOURCE}) add_library(${TARGET} STATIC ${FIELD_SOURCE})

View File

@@ -277,7 +277,7 @@ namespace polynomials {
nof_evaluations = (nof_evaluations == 0) ? this->m_nof_elements : ceil_to_power_of_two(nof_evaluations); nof_evaluations = (nof_evaluations == 0) ? this->m_nof_elements : ceil_to_power_of_two(nof_evaluations);
const bool is_same_nof_evaluations = nof_evaluations == this->m_nof_elements; const bool is_same_nof_evaluations = nof_evaluations == this->m_nof_elements;
const bool is_same_order = is_reversed && this->m_state == State::EvaluationsOnRou_Reversed || const bool is_same_order = is_reversed && this->m_state == State::EvaluationsOnRou_Reversed ||
(!is_reversed && State::EvaluationsOnRou_Natural); (!is_reversed && this->m_state == State::EvaluationsOnRou_Natural);
const bool is_already_in_state = is_same_nof_evaluations && is_same_order; const bool is_already_in_state = is_same_nof_evaluations && is_same_order;
if (is_already_in_state) { return; } if (is_already_in_state) { return; }

View File

@@ -10,14 +10,14 @@ FetchContent_Declare(
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest) FetchContent_MakeAvailable(googletest)
add_executable(runner runner.cu) # TODO link to icicle rather than including source files add_executable(runner runner.cu) # TODO link to icicle rather than including source files
target_include_directories(runner PUBLIC ${CMAKE_SOURCE_DIR}/include/) target_include_directories(runner PUBLIC ${CMAKE_SOURCE_DIR}/include/)
target_link_libraries(runner GTest::gtest_main) target_link_libraries(runner GTest::gtest_main)
set_target_properties(runner PROPERTIES CUDA_SEPARABLE_COMPILATION ON) set_target_properties(runner PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
# polynomial test-bench # polynomial test-bench
if (FIELD OR CURVE) set(POLY_UNSUPPORTED_FIELD grumpkin)
if (NOT FIELD IN_LIST POLY_UNSUPPORTED_FIELD)
add_executable(polynomial_tb polynomial_test.cu) add_executable(polynomial_tb polynomial_test.cu)
target_link_libraries(polynomial_tb GTest::gtest_main icicle_field pthread) target_link_libraries(polynomial_tb GTest::gtest_main icicle_field pthread)
if (CURVE) if (CURVE)

View File

@@ -94,12 +94,14 @@ public:
const int deg_rhs = rhs.degree(); const int deg_rhs = rhs.degree();
ASSERT_EQ(deg_lhs, deg_rhs); ASSERT_EQ(deg_lhs, deg_rhs);
auto lhs_coeffs = std::make_unique<scalar_t[]>(deg_lhs); const int nof_elements_to_compare = (deg_lhs < 0) ? 1 : deg_lhs + 1;
auto rhs_coeffs = std::make_unique<scalar_t[]>(deg_rhs);
lhs.copy_coeffs(lhs_coeffs.get(), 1, deg_lhs - 1);
rhs.copy_coeffs(rhs_coeffs.get(), 1, deg_rhs - 1);
ASSERT_EQ(0, memcmp(lhs_coeffs.get(), rhs_coeffs.get(), deg_lhs * sizeof(scalar_t))); auto lhs_coeffs = std::make_unique<scalar_t[]>(nof_elements_to_compare);
auto rhs_coeffs = std::make_unique<scalar_t[]>(nof_elements_to_compare);
lhs.copy_coeffs(lhs_coeffs.get(), 0, nof_elements_to_compare - 1);
rhs.copy_coeffs(rhs_coeffs.get(), 0, nof_elements_to_compare - 1);
ASSERT_EQ(0, memcmp(lhs_coeffs.get(), rhs_coeffs.get(), nof_elements_to_compare * sizeof(scalar_t)));
} }
static Polynomial_t vanishing_polynomial(int degree) static Polynomial_t vanishing_polynomial(int degree)
@@ -417,16 +419,22 @@ TEST_F(PolynomialTest, View)
const int size = 1 << 6; const int size = 1 << 6;
auto f = randomize_polynomial(size); auto f = randomize_polynomial(size);
auto [d_coeff, N, device_id] = f.get_coefficients_view(); {
auto [d_coeff, N, device_id] = f.get_coefficients_view();
EXPECT_EQ(d_coeff.isValid(), true); EXPECT_EQ(d_coeff.isValid(), true);
auto g = f + f; auto g = f + f;
// expecting the view to remain valid in that case // expecting the view to remain valid in that case
EXPECT_EQ(d_coeff.isValid(), true); EXPECT_EQ(d_coeff.isValid(), true);
f += f; f += f;
// expecting view to be invalidated since f is modified // expecting view to be invalidated since f is modified
EXPECT_EQ(d_coeff.isValid(), false); EXPECT_EQ(d_coeff.isValid(), false);
}
auto [d_evals, N, device_id] = f.get_rou_evaluations_view();
auto g = Polynomial_t::from_rou_evaluations(d_evals.get(), N);
assert_equal(f, g);
} }
TEST_F(PolynomialTest, interpolation) TEST_F(PolynomialTest, interpolation)