From d772b1b97e38370473b6d84d26235f7b53278640 Mon Sep 17 00:00:00 2001 From: Yuval Shekel Date: Tue, 20 Aug 2024 13:52:53 +0300 Subject: [PATCH] rework cmake option features --- icicle_v3/CMakeLists.txt | 31 ++++--- icicle_v3/backend/cpu/CMakeLists.txt | 10 ++- icicle_v3/cmake/curve.cmake | 86 ++++++++++++-------- icicle_v3/cmake/field.cmake | 102 +++++++++++++----------- icicle_v3/cmake/fields_and_curves.cmake | 17 ++++ icicle_v3/cmake/target_editor.cmake | 73 +++++++++++++++++ icicle_v3/tests/test_field_api.cpp | 4 +- 7 files changed, 225 insertions(+), 98 deletions(-) create mode 100644 icicle_v3/cmake/fields_and_curves.cmake create mode 100644 icicle_v3/cmake/target_editor.cmake diff --git a/icicle_v3/CMakeLists.txt b/icicle_v3/CMakeLists.txt index 78d1cb65f..ba9500029 100644 --- a/icicle_v3/CMakeLists.txt +++ b/icicle_v3/CMakeLists.txt @@ -19,17 +19,18 @@ message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") set(CMAKE_POSITION_INDEPENDENT_CODE ON) -# TODO Yuval remove those flags. Frontend will always have everything. -# CUDA backend may do it for faster dev. +# Build options +option(BUILD_TESTS "Build unit tests. Default=OFF" OFF) +option(CPU_BACKEND "Build CPU backend. Default=ON" ON) +option(CUDA_BACKEND "Branch/commit to pull for CUDA backend or `local` if under icicle/backend/cuda. Default=OFF" OFF) + +# features that some fields/curves have and some don't. +# By default, it is defined in [TODO Yuval]. Override the option manually to disable features. option(NTT "Build NTT" ON) +option(ECNTT "Build ECNTT" ON) option(MSM "Build MSM" ON) -option(EXT_FIELD "Build extension field" OFF) -option(ECNTT "Build ECNTT" OFF) -option(G2 "Build G2" OFF) -# REMOVE END -option(BUILD_TESTS "Build unit tests" OFF) -option(CPU_BACKEND "Build CPU backend" ON) -option(CUDA_BACKEND "Branch/commit to pull for CUDA backend, local path or OFF to disable pulling" OFF) +option(G2 "Build G2 MSM" ON) +option(EXT_FIELD "Build extension field" ON) # device API library add_library(icicle_device SHARED @@ -62,11 +63,15 @@ endif() # curve is building the scalar field too if(CURVE) - check_curve() - setup_curve_target() + set(CURVE_INDEX -1) + set(FEATURES_STRING "") + check_curve(${CURVE} CURVE_INDEX FEATURES_STRING) + setup_curve_target(${CURVE} ${CURVE_INDEX} ${FEATURES_STRING}) elseif(FIELD) - check_field() - setup_field_target() + set(FIELD_INDEX -1) + set(FEATURES_STRING "") + check_field(${FIELD} FIELD_INDEX FEATURES_STRING) + setup_field_target(${FIELD} ${FIELD_INDEX} ${FEATURES_STRING}) endif() if (CPU_BACKEND) diff --git a/icicle_v3/backend/cpu/CMakeLists.txt b/icicle_v3/backend/cpu/CMakeLists.txt index 733b3d6a1..5467d3da6 100644 --- a/icicle_v3/backend/cpu/CMakeLists.txt +++ b/icicle_v3/backend/cpu/CMakeLists.txt @@ -7,20 +7,22 @@ target_sources(icicle_device PRIVATE src/cpu_device_api.cpp) # field API library if (FIELD) target_sources(icicle_field PRIVATE - src/field/cpu_vec_ops.cpp + src/field/cpu_vec_ops.cpp ) if (NTT) target_sources(icicle_field PRIVATE src/field/cpu_ntt.cpp src/polynomials/cpu_polynomial_backend.cpp) - endif() + endif() target_include_directories(icicle_field PRIVATE include) endif() # FIELD # curve API library if (CURVE) -target_sources(icicle_curve PRIVATE - src/curve/cpu_msm.cpp + target_sources(icicle_curve PRIVATE src/curve/cpu_mont_conversion.cpp ) + if (MSM) + target_sources(icicle_curve PRIVATE src/curve/cpu_msm.cpp) + endif() if (ECNTT) target_sources(icicle_curve PRIVATE src/curve/cpu_ecntt.cpp) endif() diff --git a/icicle_v3/cmake/curve.cmake b/icicle_v3/cmake/curve.cmake index 73e6067bc..63fc94ca4 100644 --- a/icicle_v3/cmake/curve.cmake +++ b/icicle_v3/cmake/curve.cmake @@ -1,49 +1,71 @@ -function(check_curve) - set(SUPPORTED_CURVES bn254;bls12_381;bls12_377;bw6_761;grumpkin) +include(cmake/fields_and_curves.cmake) +include(cmake/target_editor.cmake) +function(extract_curve_names CURVE_NAMES_OUT) + set(CURVE_NAMES "") + + foreach (ITEM ${ICICLE_CURVES}) + string(REPLACE ":" ";" ITEM_SPLIT ${ITEM}) + list(GET ITEM_SPLIT 1 CURVE_NAME) + list(APPEND CURVE_NAMES ${CURVE_NAME}) + endforeach() + + # Output the list of curve names + set(${CURVE_NAMES_OUT} "${CURVE_NAMES}" PARENT_SCOPE) +endfunction() + +function(check_curve CURVE CURVE_INDEX_OUT FEATURES_STRING_OUT) set(IS_CURVE_SUPPORTED FALSE) - set(I 0) - foreach (SUPPORTED_CURVE ${SUPPORTED_CURVES}) - math(EXPR I "${I} + 1") - if (CURVE STREQUAL SUPPORTED_CURVE) - add_compile_definitions(FIELD_ID=${I}) - add_compile_definitions(CURVE_ID=${I}) + foreach (ITEM ${ICICLE_CURVES}) + string(REPLACE ":" ";" ITEM_SPLIT ${ITEM}) + list(GET ITEM_SPLIT 0 CURVE_INDEX) + list(GET ITEM_SPLIT 1 CURVE_NAME) + list(GET ITEM_SPLIT 2 FEATURES_STRING) + + if (CURVE STREQUAL CURVE_NAME) set(IS_CURVE_SUPPORTED TRUE) + message(STATUS "building CURVE_NAME=${CURVE_NAME} ; CURVE_INDEX=${CURVE_INDEX} ; FEATURES=${FEATURES_STRING}") + # Output the CURVE_INDEX and FEATURES_STRING + set(${CURVE_INDEX_OUT} "${CURVE_INDEX}" PARENT_SCOPE) + set(${FEATURES_STRING_OUT} "${FEATURES_STRING}" PARENT_SCOPE) + break() endif () endforeach() if (NOT IS_CURVE_SUPPORTED) - message( FATAL_ERROR "The value of CURVE variable: ${CURVE} is not one of the supported curves: ${SUPPORTED_CURVES}" ) + set(ALL_CURVES "") + extract_curve_names(ALL_CURVES) + message(FATAL_ERROR "The value of CURVE variable: ${CURVE} is not supported: choose from [${ALL_CURVES}]") endif () endfunction() -function(setup_curve_target) - set(FIELD ${CURVE}) - setup_field_target() - add_library(icicle_curve SHARED - src/msm.cpp - src/curves/ffi_extern.cpp - src/curves/montgomery_conversion.cpp - ) - target_link_libraries(icicle_curve PUBLIC icicle_device icicle_field pthread) +function(setup_curve_target CURVE_NAME CURVE_INDEX FEATURES_STRING) + # the scalar field of the curve is built to a field library (like babybear is built) + setup_field_target(${CURVE_NAME} ${CURVE_INDEX} ${FEATURES_STRING}) + + add_library(icicle_curve SHARED) + + # Split FEATURES_STRING into a list using "," as the separator + string(REPLACE "," ";" FEATURES_LIST ${FEATURES_STRING}) + + # customize the curve lib to choose what to include + handle_curve(icicle_curve) # basic curve and field methods, including vec ops + # Handle features + handle_msm(icicle_curve "${FEATURES_LIST}") + handle_g2(icicle_curve "${FEATURES_LIST}") + handle_ecntt(icicle_curve "${FEATURES_LIST}") + # Add additional feature handling calls here + set_target_properties(icicle_curve PROPERTIES OUTPUT_NAME "icicle_curve_${CURVE}") + target_link_libraries(icicle_curve PUBLIC icicle_device icicle_field pthread) - # Make sure CURVE is defined in the cache for backends to see + # Ensure CURVE is defined in the cache for backends to see set(CURVE "${CURVE}" CACHE STRING "") - target_compile_definitions(icicle_curve PUBLIC CURVE=${CURVE}) - if (G2) - set(G2 "${G2}" CACHE STRING "") - target_compile_definitions(icicle_curve PUBLIC G2=${G2}) - endif() - if (ECNTT) - target_sources(icicle_curve PRIVATE src/ecntt.cpp) - set(ECNTT "${ECNTT}" CACHE STRING "") - target_compile_definitions(icicle_curve PUBLIC ECNTT=${ECNTT}) - endif() + target_compile_definitions(icicle_curve PUBLIC CURVE=${CURVE} CURVE_ID=${CURVE_INDEX}) install(TARGETS icicle_curve - RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/lib" - LIBRARY DESTINATION "${CMAKE_INSTALL_PREFIX}/lib" - ARCHIVE DESTINATION "${CMAKE_INSTALL_PREFIX}/lib") + RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/" + LIBRARY DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/" + ARCHIVE DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/") endfunction() \ No newline at end of file diff --git a/icicle_v3/cmake/field.cmake b/icicle_v3/cmake/field.cmake index f783ce1f6..f7eb17843 100644 --- a/icicle_v3/cmake/field.cmake +++ b/icicle_v3/cmake/field.cmake @@ -1,59 +1,67 @@ -function(check_field) - set(SUPPORTED_FIELDS babybear;stark252) +include(cmake/fields_and_curves.cmake) +include(cmake/target_editor.cmake) +function(extract_field_names FIELD_NAMES_OUT) + set(FIELD_NAMES "") + + foreach (ITEM ${ICICLE_FIELDS}) + string(REPLACE ":" ";" ITEM_SPLIT ${ITEM}) + list(GET ITEM_SPLIT 1 FIELD_NAME) + list(APPEND FIELD_NAMES ${FIELD_NAME}) + endforeach() + + # Output the list of field names + set(${FIELD_NAMES_OUT} "${FIELD_NAMES}" PARENT_SCOPE) +endfunction() + +function(check_field FIELD FIELD_INDEX_OUT FEATURES_STRING_OUT) set(IS_FIELD_SUPPORTED FALSE) - set(I 1000) - foreach (SUPPORTED_FIELD ${SUPPORTED_FIELDS}) - math(EXPR I "${I} + 1") - if (FIELD STREQUAL SUPPORTED_FIELD) - add_compile_definitions(FIELD_ID=${I}) + foreach (ITEM ${ICICLE_FIELDS}) + string(REPLACE ":" ";" ITEM_SPLIT ${ITEM}) + list(GET ITEM_SPLIT 0 FIELD_INDEX) + list(GET ITEM_SPLIT 1 FIELD_NAME) + list(GET ITEM_SPLIT 2 FEATURES_STRING) + + if (FIELD STREQUAL FIELD_NAME) set(IS_FIELD_SUPPORTED TRUE) + message(STATUS "building FIELD_NAME=${FIELD_NAME} ; FIELD_INDEX=${FIELD_INDEX} ; FEATURES=${FEATURES_STRING}") + # Output the FIELD_INDEX and FEATURES_STRING + set(${FIELD_INDEX_OUT} "${FIELD_INDEX}" PARENT_SCOPE) + set(${FEATURES_STRING_OUT} "${FEATURES_STRING}" PARENT_SCOPE) + break() endif () endforeach() if (NOT IS_FIELD_SUPPORTED) - message( FATAL_ERROR "The value of FIELD variable: ${FIELD} is not one of the supported fields: ${SUPPORTED_FIELDS}" ) + set(ALL_FIELDS "") + extract_field_names(ALL_FIELDS) + message(FATAL_ERROR "The value of FIELD variable: ${FIELD} is not supported: choose from [${ALL_FIELDS}]") endif () endfunction() -function(setup_field_target) - add_library(icicle_field SHARED - src/fields/ffi_extern.cpp - src/vec_ops.cpp - src/matrix_ops.cpp - ) - # handle APIs that are for some curves only - add_ntt_sources_or_disable() - set_target_properties(icicle_field PROPERTIES OUTPUT_NAME "icicle_field_${FIELD}") - target_link_libraries(icicle_field PUBLIC icicle_device pthread) - - # Make sure FIELD is defined in the cache for backends to see - set(FIELD "${FIELD}" CACHE STRING "") - target_compile_definitions(icicle_field PUBLIC FIELD=${FIELD}) - if (EXT_FIELD) - set(EXT_FIELD "${EXT_FIELD}" CACHE STRING "") - target_compile_definitions(icicle_field PUBLIC EXT_FIELD=${EXT_FIELD}) - endif() - - install(TARGETS icicle_field - RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/" - LIBRARY DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/" - ARCHIVE DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/") +function(setup_field_target FIELD_NAME FIELD_INDEX FEATURES_STRING) + add_library(icicle_field SHARED) + + # Split FEATURES_STRING into a list using "," as the separator + string(REPLACE "," ";" FEATURES_LIST ${FEATURES_STRING}) + + # customize the field lib to choose what to include + handle_field(icicle_field) # basic field methods, including vec ops + # Handle features + handle_ntt(icicle_field "${FEATURES_LIST}") + handle_ext_field(icicle_field "${FEATURES_LIST}") + # Add additional feature handling calls here + + set_target_properties(icicle_field PROPERTIES OUTPUT_NAME "icicle_field_${FIELD}") + target_link_libraries(icicle_field PUBLIC icicle_device pthread) + + # Ensure FIELD is defined in the cache for backends to see + set(FIELD "${FIELD_NAME}" CACHE STRING "") + add_compile_definitions(FIELD=${FIELD} FIELD_ID=${FIELD_INDEX}) + + install(TARGETS icicle_field + RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/" + LIBRARY DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/" + ARCHIVE DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/") endfunction() -function(add_ntt_sources_or_disable) - set(SUPPORTED_FIELDS_WITHOUT_NTT grumpkin) - - if (NOT FIELD IN_LIST SUPPORTED_FIELDS_WITHOUT_NTT) - add_compile_definitions(NTT_ENABLED) - target_sources(icicle_field PRIVATE - src/ntt.cpp - src/polynomials/polynomials.cpp - src/polynomials/polynomials_c_api.cpp - src/polynomials/polynomials_abstract_factory.cpp - ) - else() - set(NTT OFF CACHE BOOL "NTT not available for field" FORCE) - endif() - -endfunction() \ No newline at end of file diff --git a/icicle_v3/cmake/fields_and_curves.cmake b/icicle_v3/cmake/fields_and_curves.cmake new file mode 100644 index 000000000..f5022eb66 --- /dev/null +++ b/icicle_v3/cmake/fields_and_curves.cmake @@ -0,0 +1,17 @@ + +# Define available fields with an index and their supported features +# Format: index:field:features +set(ICICLE_FIELDS + 1001:babybear:NTT,EXT_FIELD + 1002:stark252:NTT +) + +# Define available curves with an index and their supported features +# Format: index:curve:features +set(ICICLE_CURVES + 1:bn254:NTT,MSM,G2,ECNTT + 2:bls12_381:NTT,MSM,G2,ECNTT + 3:bls12_377:NTT,MSM,G2,ECNTT + 4:bw6_761:NTT,MSM,G2,ECNTT + 5:grumpkin:MSM +) \ No newline at end of file diff --git a/icicle_v3/cmake/target_editor.cmake b/icicle_v3/cmake/target_editor.cmake new file mode 100644 index 000000000..4e8e433a5 --- /dev/null +++ b/icicle_v3/cmake/target_editor.cmake @@ -0,0 +1,73 @@ + +# The following functions, each adds a function to a target. +# In addition, some can check feature is enabled for target, given FEATURE_LIST. + +function(handle_field TARGET) + target_sources(${TARGET} PRIVATE + src/fields/ffi_extern.cpp + src/vec_ops.cpp + src/matrix_ops.cpp + ) +endfunction() + +function(handle_curve TARGET) + target_sources(${TARGET} PRIVATE + src/curves/ffi_extern.cpp + src/curves/montgomery_conversion.cpp + ) +endfunction() + +function(handle_ntt TARGET FEATURE_LIST) + if(NTT AND "NTT" IN_LIST FEATURE_LIST) + target_compile_definitions(${TARGET} PUBLIC NTT=${NTT}) + target_sources(${TARGET} PRIVATE + src/ntt.cpp + src/polynomials/polynomials.cpp + src/polynomials/polynomials_c_api.cpp + src/polynomials/polynomials_abstract_factory.cpp + ) + set(NTT ON CACHE BOOL "Enable NTT feature" FORCE) + else() + set(NTT OFF CACHE BOOL "NTT not available for this field" FORCE) + message(STATUS "NTT not available for this field") + endif() +endfunction() + +function(handle_ext_field TARGET FEATURE_LIST) + if(EXT_FIELD AND "EXT_FIELD" IN_LIST FEATURE_LIST) + target_compile_definitions(${TARGET} PUBLIC EXT_FIELD=${EXT_FIELD}) + set(EXT_FIELD ON CACHE BOOL "Enable EXT_FIELD feature" FORCE) + else() + set(EXT_FIELD OFF CACHE BOOL "EXT_FIELD not available for this field" FORCE) + endif() +endfunction() + +function(handle_msm TARGET FEATURE_LIST) + if(MSM AND "MSM" IN_LIST FEATURE_LIST) + target_compile_definitions(${TARGET} PUBLIC MSM=${MSM}) + target_sources(${TARGET} PRIVATE src/msm.cpp) + set(MSM ON CACHE BOOL "Enable MSM feature" FORCE) + else() + set(MSM OFF CACHE BOOL "MSM not available for this curve" FORCE) + endif() +endfunction() + +function(handle_g2 TARGET FEATURE_LIST) + if(G2 AND "G2" IN_LIST FEATURE_LIST) + target_compile_definitions(${TARGET} PUBLIC G2=${G2}) + set(G2 ON CACHE BOOL "Enable G2 feature" FORCE) + else() + set(G2 OFF CACHE BOOL "G2 not available for this curve" FORCE) + endif() +endfunction() + +function(handle_ecntt TARGET FEATURE_LIST) + if(ECNTT AND "ECNTT" IN_LIST FEATURE_LIST) + target_compile_definitions(${TARGET} PUBLIC ECNTT=${ECNTT}) + target_sources(icicle_curve PRIVATE src/ecntt.cpp) + set(ECNTT ON CACHE BOOL "Enable ECNTT feature" FORCE) + else() + set(ECNTT OFF CACHE BOOL "ECNTT not available for this curve" FORCE) + endif() +endfunction() + diff --git a/icicle_v3/tests/test_field_api.cpp b/icicle_v3/tests/test_field_api.cpp index cfd9e5fb7..593c9b809 100644 --- a/icicle_v3/tests/test_field_api.cpp +++ b/icicle_v3/tests/test_field_api.cpp @@ -294,7 +294,7 @@ TYPED_TEST(FieldApiTest, Slice) ASSERT_EQ(0, memcmp(elements_ref.get(), elements_out.get(), size * sizeof(TypeParam))); } -#ifdef NTT_ENABLED +#ifdef NTT TYPED_TEST(FieldApiTest, ntt) { srand(time(0)); @@ -383,7 +383,7 @@ TYPED_TEST(FieldApiTest, ntt) ASSERT_EQ(0, memcmp(out_main.get(), out_ref.get(), total_size * sizeof(scalar_t))); } -#endif // NTT_ENABLED +#endif // NTT int main(int argc, char** argv) {