From 996f388c4e849f87d641484688223ba0f059320a Mon Sep 17 00:00:00 2001 From: Yuval Shekel Date: Tue, 4 Jun 2024 19:22:34 +0300 Subject: [PATCH] montgomery conversion G1 --- icicle_v3/CMakeLists.txt | 17 ++-- icicle_v3/backend/cpu/CMakeLists.txt | 5 +- .../cpu/src/curve/cpu_mont_conversion.cpp | 23 +++++ icicle_v3/backend/cuda/CMakeLists.txt | 2 +- icicle_v3/cmake/curve.cmake | 1 + icicle_v3/include/icicle/curves/affine.h | 5 ++ .../icicle/curves/montgomery_conversion.h | 83 +++++++++++++++++++ icicle_v3/include/icicle/curves/projective.h | 1 + icicle_v3/include/icicle/utils/log.h | 22 ++++- .../src/curves/montgomery_conversion.cpp | 40 +++++++++ icicle_v3/tests/CMakeLists.txt | 2 +- icicle_v3/tests/test_curve_api.cpp | 29 +++++++ 12 files changed, 217 insertions(+), 13 deletions(-) create mode 100644 icicle_v3/backend/cpu/src/curve/cpu_mont_conversion.cpp create mode 100644 icicle_v3/include/icicle/curves/montgomery_conversion.h create mode 100644 icicle_v3/src/curves/montgomery_conversion.cpp diff --git a/icicle_v3/CMakeLists.txt b/icicle_v3/CMakeLists.txt index a6f59f001e..6c416702b8 100644 --- a/icicle_v3/CMakeLists.txt +++ b/icicle_v3/CMakeLists.txt @@ -25,20 +25,19 @@ target_link_libraries(icicle_device PUBLIC dl) target_include_directories(icicle_device PUBLIC include) if((DEFINED CURVE) AND (DEFINED FIELD)) - message( FATAL_ERROR "CURVE and FIELD cannot be defined at the same time" ) -endif () - -# field library -if(FIELD) - check_field() - setup_field_target() + if(NOT ("${CURVE}" STREQUAL "${FIELD}")) + message(FATAL_ERROR "CURVE and FIELD should be defined at the same time unless they are equal") + endif() endif() +# curve is building the scalar field too if(CURVE) check_curve() setup_curve_target() -endif () - +elseif(FIELD) + check_field() + setup_field_target() +endif() if (BUILD_CPU_BE) add_subdirectory(backend/cpu) diff --git a/icicle_v3/backend/cpu/CMakeLists.txt b/icicle_v3/backend/cpu/CMakeLists.txt index 084440f3de..9f4d42bfff 100644 --- a/icicle_v3/backend/cpu/CMakeLists.txt +++ b/icicle_v3/backend/cpu/CMakeLists.txt @@ -21,7 +21,10 @@ set_target_properties(icicle_cpu_field PROPERTIES OUTPUT_NAME "icicle_cpu_field_ # curve API library if (CURVE) - add_library(icicle_cpu_curve SHARED src/curve/cpu_msm.cpp) + add_library(icicle_cpu_curve SHARED + src/curve/cpu_msm.cpp + src/curve/cpu_mont_conversion.cpp + ) target_link_libraries(icicle_cpu_curve PUBLIC icicle_device icicle_curve) set_target_properties(icicle_cpu_curve PROPERTIES OUTPUT_NAME "icicle_cpu_curve_${CURVE}") endif() diff --git a/icicle_v3/backend/cpu/src/curve/cpu_mont_conversion.cpp b/icicle_v3/backend/cpu/src/curve/cpu_mont_conversion.cpp new file mode 100644 index 0000000000..808aa1f23f --- /dev/null +++ b/icicle_v3/backend/cpu/src/curve/cpu_mont_conversion.cpp @@ -0,0 +1,23 @@ + +#include "icicle/curves/montgomery_conversion.h" +#include "icicle/errors.h" +#include "icicle/runtime.h" +#include "icicle/utils/log.h" + +#include "icicle/curves/curve_config.h" + +using namespace curve_config; +using namespace icicle; + +template +eIcicleError cpu_convert_mont( + const Device& device, const T* input, size_t n, bool is_into, const ConvertMontgomeryConfig& config, T* output) +{ + for (size_t i = 0; i < n; ++i) { + output[i] = is_into ? T::to_montgomery(input[i]) : T::from_montgomery(input[i]); + } + return eIcicleError::SUCCESS; +} + +REGISTER_AFFINE_CONVERT_MONTGOMERY_BACKEND("CPU", cpu_convert_mont); +REGISTER_PROJECTIVE_CONVERT_MONTGOMERY_BACKEND("CPU", cpu_convert_mont); \ No newline at end of file diff --git a/icicle_v3/backend/cuda/CMakeLists.txt b/icicle_v3/backend/cuda/CMakeLists.txt index 18c4430c7c..28e59e8232 100644 --- a/icicle_v3/backend/cuda/CMakeLists.txt +++ b/icicle_v3/backend/cuda/CMakeLists.txt @@ -7,7 +7,7 @@ include(cmake/Common.cmake) set_env() set_gpu_env() -find_package(CUDA REQUIRED) +find_package(CUDAToolkit REQUIRED) # device API library add_library(icicle_cuda_device SHARED src/cuda_device_api.cu) diff --git a/icicle_v3/cmake/curve.cmake b/icicle_v3/cmake/curve.cmake index 83bea7ecb0..ba205c99c7 100644 --- a/icicle_v3/cmake/curve.cmake +++ b/icicle_v3/cmake/curve.cmake @@ -24,6 +24,7 @@ function(setup_curve_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) # for thread local device set_target_properties(icicle_curve PROPERTIES OUTPUT_NAME "icicle_curve_${CURVE}") diff --git a/icicle_v3/include/icicle/curves/affine.h b/icicle_v3/include/icicle/curves/affine.h index dff7fd1128..b2564d372b 100644 --- a/icicle_v3/include/icicle/curves/affine.h +++ b/icicle_v3/include/icicle/curves/affine.h @@ -32,6 +32,11 @@ class Affine return (xs.x == ys.x) && (xs.y == ys.y); } + friend HOST_DEVICE_INLINE bool operator!=(const Affine& xs, const Affine& ys) + { + return !(xs==ys); + } + friend HOST_INLINE std::ostream& operator<<(std::ostream& os, const Affine& point) { os << "x: " << point.x << "; y: " << point.y; diff --git a/icicle_v3/include/icicle/curves/montgomery_conversion.h b/icicle_v3/include/icicle/curves/montgomery_conversion.h new file mode 100644 index 0000000000..2110bbf659 --- /dev/null +++ b/icicle_v3/include/icicle/curves/montgomery_conversion.h @@ -0,0 +1,83 @@ +#pragma once + +#include + +#include "icicle/errors.h" +#include "icicle/runtime.h" +#include "icicle/utils/utils.h" +#include "icicle/config_extension.h" + +#include "icicle/curves/affine.h" +#include "icicle/curves/projective.h" +#include "icicle/fields/field.h" +#include "icicle/curves/curve_config.h" + +using namespace curve_config; + +namespace icicle { + + /*************************** Frontend APIs ***************************/ + + struct ConvertMontgomeryConfig { + icicleStreamHandle stream; /**< stream for async execution. */ + bool is_input_on_device; + bool is_output_on_device; + bool is_async; + + ConfigExtension ext; /** backend specific extensions*/ + }; + + static ConvertMontgomeryConfig default_convert_montgomery_config() + { + ConvertMontgomeryConfig config = { + nullptr, // stream + false, // is_input_on_device + false, // is_output_on_device + false, // is_async + }; + return config; + } + + template + eIcicleError + points_convert_montgomery(const T* input, size_t n, bool is_into, const ConvertMontgomeryConfig& config, T* output); + + /*************************** Backend registration ***************************/ + + using AffineConvertMontImpl = std::function; + + void register_affine_convert_montgomery(const std::string& deviceType, AffineConvertMontImpl); + +#define REGISTER_AFFINE_CONVERT_MONTGOMERY_BACKEND(DEVICE_TYPE, FUNC) \ + namespace { \ + static bool UNIQUE(_reg_affine_convert_mont) = []() -> bool { \ + register_affine_convert_montgomery(DEVICE_TYPE, FUNC); \ + return true; \ + }(); \ + } + + using ProjectiveConvertMontImpl = std::function; + + void register_projective_convert_montgomery(const std::string& deviceType, ProjectiveConvertMontImpl); + +#define REGISTER_PROJECTIVE_CONVERT_MONTGOMERY_BACKEND(DEVICE_TYPE, FUNC) \ + namespace { \ + static bool UNIQUE(_reg_projective_convert_mont) = []() -> bool { \ + register_projective_convert_montgomery(DEVICE_TYPE, FUNC); \ + return true; \ + }(); \ + } + +}; // namespace icicle diff --git a/icicle_v3/include/icicle/curves/projective.h b/icicle_v3/include/icicle/curves/projective.h index 6ed5fd7b00..2b1686fa7a 100644 --- a/icicle_v3/include/icicle/curves/projective.h +++ b/icicle_v3/include/icicle/curves/projective.h @@ -30,6 +30,7 @@ class Projective FF denom = FF::inverse(point.z); return {point.x * denom, point.y * denom}; } + HOST_DEVICE_INLINE Affine to_affine() { return to_affine(*this); } static HOST_DEVICE_INLINE Projective from_affine(const Affine& point) { diff --git a/icicle_v3/include/icicle/utils/log.h b/icicle_v3/include/icicle/utils/log.h index 5c010bf8cb..9e76434fe8 100644 --- a/icicle_v3/include/icicle/utils/log.h +++ b/icicle_v3/include/icicle/utils/log.h @@ -13,7 +13,10 @@ class Log public: enum eLogLevel { Debug, Info, Warning, Error }; - Log(eLogLevel level) : level(level) {} + Log(eLogLevel level) : level{level} + { + if (level >= s_min_log_level) { oss << "[" << logLevelToString(level) << "] "; } + } ~Log() { @@ -34,6 +37,23 @@ class Log eLogLevel level; std::ostringstream oss; + // Convert log level to string + const char* logLevelToString(eLogLevel level) const + { + switch (level) { + case Debug: + return "DEBUG"; + case Info: + return "INFO"; + case Warning: + return "WARNING"; + case Error: + return "ERROR"; + default: + return ""; + } + } + // logging message with level>=s_min_log_level #if defined(NDEBUG) static inline eLogLevel s_min_log_level = eLogLevel::Info; diff --git a/icicle_v3/src/curves/montgomery_conversion.cpp b/icicle_v3/src/curves/montgomery_conversion.cpp new file mode 100644 index 0000000000..76390bedb7 --- /dev/null +++ b/icicle_v3/src/curves/montgomery_conversion.cpp @@ -0,0 +1,40 @@ +#include "icicle/curves/montgomery_conversion.h" +#include "icicle/dispatcher.h" +#include "icicle/curves/curve_config.h" + +using namespace curve_config; + +namespace icicle { + + /*************************** AFFINE CONVERT MONTGOMERY ***************************/ + ICICLE_DISPATCHER_INST(AffineConvertMont, affine_convert_montgomery, AffineConvertMontImpl); + + extern "C" eIcicleError CONCAT_EXPAND(CURVE, affine_convert_montgomery)( + const affine_t* input, size_t n, bool is_into, const ConvertMontgomeryConfig& config, affine_t* output) + { + return AffineConvertMont::execute(input, n, is_into, config, output); + } + + template <> + eIcicleError points_convert_montgomery( + const affine_t* input, size_t n, bool is_into, const ConvertMontgomeryConfig& config, affine_t* output) + { + return CONCAT_EXPAND(CURVE, affine_convert_montgomery)(input, n, is_into, config, output); + } + + /*************************** PROJECTIVE CONVERT MONTGOMERY ***************************/ + ICICLE_DISPATCHER_INST(ProjectiveConvertMont, projective_convert_montgomery, ProjectiveConvertMontImpl); + + extern "C" eIcicleError CONCAT_EXPAND(CURVE, projective_convert_montgomery)( + const projective_t* input, size_t n, bool is_into, const ConvertMontgomeryConfig& config, projective_t* output) + { + return ProjectiveConvertMont::execute(input, n, is_into, config, output); + } + + template <> + eIcicleError points_convert_montgomery( + const projective_t* input, size_t n, bool is_into, const ConvertMontgomeryConfig& config, projective_t* output) + { + return CONCAT_EXPAND(CURVE, projective_convert_montgomery)(input, n, is_into, config, output); + } +} // namespace icicle \ No newline at end of file diff --git a/icicle_v3/tests/CMakeLists.txt b/icicle_v3/tests/CMakeLists.txt index a5bf6a9423..762848b8c4 100644 --- a/icicle_v3/tests/CMakeLists.txt +++ b/icicle_v3/tests/CMakeLists.txt @@ -3,7 +3,7 @@ include(GoogleTest) include(FetchContent) FetchContent_Declare( googletest - URL https://github.com/google/googletest/archive/refs/tags/v1.13.0.zip + URL https://github.com/google/googletest/archive/refs/tags/v1.13.0.zip ) # For Windows: Prevent overriding the parent project's compiler/linker settings diff --git a/icicle_v3/tests/test_curve_api.cpp b/icicle_v3/tests/test_curve_api.cpp index da95aa98ac..45227ad046 100644 --- a/icicle_v3/tests/test_curve_api.cpp +++ b/icicle_v3/tests/test_curve_api.cpp @@ -6,6 +6,7 @@ #include "icicle/runtime.h" #include "icicle/msm.h" #include "icicle/vec_ops.h" +#include "icicle/curves/montgomery_conversion.h" #include "icicle/curves/curve_config.h" using namespace curve_config; @@ -70,6 +71,34 @@ TEST_F(CurveApiTest, MSM) // TODO test something } +TEST_F(CurveApiTest, MontConversion) +{ + // Note: this test doesn't really test correct mont conversion (since there is no arithmetic in mont) but checkes that + // it does some conversion and back to original + affine_t affine_point, affine_point_converted; + projective_t projective_point, projective_point_converted; + + projective_point = projective_t::rand_host(); + affine_point = projective_point.to_affine(); + + icicle_set_device({"CPU", 0}); + + // (1) converting to mont and check not equal to original + auto config = default_convert_montgomery_config(); + points_convert_montgomery(&affine_point, 1, true /*into mont*/, config, &affine_point_converted); + points_convert_montgomery(&projective_point, 1, true /*into mont*/, config, &projective_point_converted); + + ASSERT_NE(affine_point, affine_point_converted); // check that it was converted to mont + ASSERT_NE(projective_point.x, projective_point_converted.x); // check that it was converted to mont + + // (2) converting back from mont and check equal + points_convert_montgomery(&projective_point_converted, 1, false /*from mont*/, config, &projective_point_converted); + points_convert_montgomery(&affine_point_converted, 1, false /*from mont*/, config, &affine_point_converted); + + ASSERT_EQ(affine_point, affine_point_converted); + ASSERT_EQ(projective_point, projective_point_converted); +} + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv);