diff --git a/icicle_v3/backend/cpu/src/curve/cpu_msm.cpp b/icicle_v3/backend/cpu/src/curve/cpu_msm.cpp index e69de29bb2..dd9aea5e82 100644 --- a/icicle_v3/backend/cpu/src/curve/cpu_msm.cpp +++ b/icicle_v3/backend/cpu/src/curve/cpu_msm.cpp @@ -0,0 +1,24 @@ + +#include "icicle/msm.h" +#include "icicle/errors.h" +#include "icicle/runtime.h" + +#include "icicle/curves/projective.h" +#include "icicle/curves/curve_config.h" + +using namespace curve_config; +using namespace icicle; + +eIcicleError cpu_msm( + const Device& device, + const scalar_t* scalars, + const affine_t* bases, + int msm_size, + const MSMConfig& config, + ResType* results) +{ + std::cerr << "cpu_ntt() not implemented" << std::endl; + return eIcicleError::API_NOT_IMPLEMENTED; +} + +REGISTER_MSM_BACKEND("CPU", cpu_msm); \ No newline at end of file diff --git a/icicle_v3/include/icicle/curves/projective.h b/icicle_v3/include/icicle/curves/projective.h index 2577b74209..4aee4f5101 100644 --- a/icicle_v3/include/icicle/curves/projective.h +++ b/icicle_v3/include/icicle/curves/projective.h @@ -3,6 +3,8 @@ #ifdef __CUDACC__ #include "gpu-utils/sharedmem.h" #endif // __CUDACC__ + +#include "icicle/utils/modifiers.h" #include "icicle/curves/affine.h" template diff --git a/icicle_v3/include/icicle/msm.h b/icicle_v3/include/icicle/msm.h index 3f59c932d3..94e39d638c 100644 --- a/icicle_v3/include/icicle/msm.h +++ b/icicle_v3/include/icicle/msm.h @@ -1,2 +1,138 @@ #pragma once +#include + +#include "icicle/errors.h" +#include "icicle/runtime.h" +#include "icicle/utils/utils.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 MSMConfig { + icicleStreamHandle stream; /**< stream for async execution. */ + int nof_bases; /**< Number of bases in the MSM for batched MSM. Set to 0 if all MSMs use the same bases or set to + * 'batch X #scalars' otherwise. Default value: 0 (that is reuse bases for all batch elements). */ + int precompute_factor; /**< The number of extra points to pre-compute for each point. See the + * [precompute_msm_bases](@ref precompute_msm_bases) function, `precompute_factor` passed + * there needs to be equal to the one used here. Larger values decrease the + * number of computations to make, on-line memory footprint, but increase the static + * memory footprint. Default value: 1 (i.e. don't pre-compute). */ + int batch_size; /**< The number of MSMs to compute. Default value: 1. */ + bool are_scalars_on_device; /**< True if scalars are on device and false if they're on host. Default value: + * false. */ + bool are_scalars_montgomery_form; /**< True if scalars are in Montgomery form and false otherwise. Default value: + * true. */ + bool are_points_on_device; /**< True if points are on device and false if they're on host. Default value: false. */ + bool are_points_montgomery_form; /**< True if coordinates of points are in Montgomery form and false otherwise. + * Default value: true. */ + bool are_results_on_device; /**< True if the results should be on device and false if they should be on host. If set + * to false, `is_async` won't take effect because a synchronization is needed to + * transfer results to the host. Default value: false. */ + bool is_async; /**< Whether to run the MSM asynchronously. If set to true, the MSM function will be + * non-blocking and you'd need to synchronize it explicitly by running + * `cudaStreamSynchronize` or `cudaDeviceSynchronize`. If set to false, the MSM + * function will block the current CPU thread. */ + }; + + /** + * A function that returns the default value of [MSMConfig](@ref MSMConfig) for the [MSM](@ref MSM) function. + * @return Default value of [MSMConfig](@ref MSMConfig). + */ + static MSMConfig default_msm_config() + { + MSMConfig config = { + nullptr, // stream + 0, // nof_bases + 1, // precompute_factor + 1, // batch_size + false, // are_scalars_on_device + false, // are_scalars_montgomery_form + false, // are_points_on_device + false, // are_points_montgomery_form + false, // are_results_on_device + false, // is_async + }; + return config; + } + + /** + * A function that computes MSM: \f$ MSM(s_i, P_i) = \sum_{i=1}^N s_i \cdot P_i \f$. + * @param scalars Scalars \f$ s_i \f$. In case of batch MSM, the scalars from all MSMs are concatenated. + * @param bases Bases \f$ P_i \f$. In case of batch MSM, all *unique* points are concatenated. + * So, if for example all MSMs share the same base points, they can be repeated only once. + * @param msm_size MSM size \f$ N \f$. If a batch of MSMs (which all need to have the same size) is computed, this is + * the size of 1 MSM. + * @param config [MSMConfig](@ref MSMConfig) used in this MSM. + * @param results Buffer for the result (or results in the case of batch MSM). + * @tparam S Scalar field type. + * @tparam A The type of points \f$ \{P_i\} \f$ which is typically an [affine + * Weierstrass](https://hyperelliptic.org/EFD/g1p/auto-shortw.html) point. + * @tparam P Output type, which is typically a [projective + * Weierstrass](https://hyperelliptic.org/EFD/g1p/auto-shortw-projective.html) point in our codebase. + * @return `SUCCESS` if the execution was successful and an error code otherwise. + * + */ + template + eIcicleError msm(const S* scalars, const A* bases, int msm_size, const MSMConfig& config, P* results); + + /** + * A function that precomputes MSM bases by extending them with their shifted copies. + * e.g.: + * Original points: \f$ P_0, P_1, P_2, ... P_{size} \f$ + * Extended points: \f$ P_0, P_1, P_2, ... P_{size}, 2^{l}P_0, 2^{l}P_1, ..., 2^{l}P_{size}, + * 2^{2l}P_0, 2^{2l}P_1, ..., 2^{2cl}P_{size}, ... \f$ + * @param bases Bases \f$ P_i \f$. In case of batch MSM, all *unique* points are concatenated. + * @param bases_size Number of bases. + * @param precompute_factor The number of total precomputed points for each base (including the base itself). + * @param _c This is currently unused, but in the future precomputation will need to be aware of + * the `c` value used in MSM (see [MSMConfig](@ref MSMConfig)). So to avoid breaking your code with this + * upcoming change, make sure to use the same value of `c` in this function and in respective MSMConfig. + * @param are_bases_on_device Whether the bases are on device. + * @param ctx Device context specifying device id and stream to use. + * @param output_bases Device-allocated buffer of size bases_size * precompute_factor for the extended bases. + * @tparam A The type of points \f$ \{P_i\} \f$ which is typically an [affine + * Weierstrass](https://hyperelliptic.org/EFD/g1p/auto-shortw.html) point. + * @return `SUCCESS` if the execution was successful and an error code otherwise. + * + */ + template + eIcicleError precompute_msm_bases( + A* bases, + int bases_size, + int precompute_factor, + int c, + bool are_bases_on_device, + icicleStreamHandle stream, + A* output_bases); + + /*************************** Backend registration ***************************/ + +#define ResType affine_t + + using MsmImpl = std::function; + + void register_msm(const std::string& deviceType, MsmImpl impl); + +#define REGISTER_MSM_BACKEND(DEVICE_TYPE, FUNC) \ + namespace { \ + static bool _reg_msm = []() -> bool { \ + register_msm(DEVICE_TYPE, FUNC); \ + return true; \ + }(); \ + } + +}; // namespace icicle \ No newline at end of file diff --git a/icicle_v3/src/msm.cpp b/icicle_v3/src/msm.cpp index 27f6bd21a5..5208dcb417 100644 --- a/icicle_v3/src/msm.cpp +++ b/icicle_v3/src/msm.cpp @@ -1 +1,25 @@ -#include "icicle/msm.h" \ No newline at end of file +#include "icicle/msm.h" +#include "icicle/dispatcher.h" +#include "icicle/curves/curve_config.h" + +using namespace curve_config; + +namespace icicle { + + /*************************** MSM ***************************/ + ICICLE_DISPATCHER_INST(MsmDispatcher, msm, MsmImpl); + + extern "C" eIcicleError CONCAT_EXPAND(CURVE, msm)( + const scalar_t* scalars, const affine_t* bases, int msm_size, const MSMConfig& config, ResType* results) + { + return MsmDispatcher::execute(scalars, bases, msm_size, config, results); + } + + template <> + eIcicleError + msm(const scalar_t* scalars, const affine_t* bases, int msm_size, const MSMConfig& config, ResType* results) + { + return CONCAT_EXPAND(CURVE, msm)(scalars, bases, msm_size, config, results); + } + +} // namespace icicle \ No newline at end of file