#include #include #include #include "icicle/runtime.h" #include "icicle/api/bn254.h" using namespace bn254; #include "examples_utils.h" int main(int argc, char* argv[]) { try_load_and_set_backend_device(argc, argv); std::cout << "\nIcicle example: Muli-Scalar Multiplication (MSM)" << std::endl; std::cout << "Example parameters" << std::endl; int batch_size = 1; unsigned msm_size = 1 << 10; int N = batch_size * msm_size; std::cout << "Batch size: " << batch_size << std::endl; std::cout << "MSM size: " << msm_size << std::endl; std::cout << "\nPart I: use G1 points" << std::endl; std::cout << "Generating random inputs on-host" << std::endl; auto scalars = std::make_unique(N); auto points = std::make_unique(N); projective_t result; scalar_t::rand_host_many(scalars.get(), N); projective_t::rand_host_many(points.get(), N); std::cout << "Using default MSM configuration with on-host inputs" << std::endl; auto config = default_msm_config(); config.batch_size = batch_size; std::cout << "\nRunning MSM kernel with on-host inputs" << std::endl; // Execute the MSM kernel START_TIMER(MSM_host_mem); ICICLE_CHECK(bn254_msm(scalars.get(), points.get(), msm_size, config, &result)); END_TIMER(MSM_host_mem, "MSM from host-memory took"); std::cout << projective_t::to_affine(result) << std::endl; DeviceProperties device_props; ICICLE_CHECK(icicle_get_device_properties(device_props)); // If device does not share memory with host, copy inputs explicitly and execute msm with device pointers if (!device_props.using_host_memory) { std::cout << "\nReconfiguring MSM to use on-device inputs" << std::endl; config.are_results_on_device = true; config.are_scalars_on_device = true; config.are_points_on_device = true; std::cout << "Copying inputs to-device" << std::endl; scalar_t* scalars_d; affine_t* points_d; projective_t* result_d; ICICLE_CHECK(icicle_malloc((void**)&scalars_d, sizeof(scalar_t) * N)); ICICLE_CHECK(icicle_malloc((void**)&points_d, sizeof(affine_t) * N)); ICICLE_CHECK(icicle_malloc((void**)&result_d, sizeof(projective_t))); ICICLE_CHECK(icicle_copy(scalars_d, scalars.get(), sizeof(scalar_t) * N)); ICICLE_CHECK(icicle_copy(points_d, points.get(), sizeof(affine_t) * N)); std::cout << "Running MSM kernel with on-device inputs" << std::endl; // Execute the MSM kernel START_TIMER(MSM_device_mem); ICICLE_CHECK(msm(scalars_d, points_d, msm_size, config, result_d)); END_TIMER(MSM_device_mem, "MSM from device-memory took"); // Copy the result back to the host icicle_copy(&result, result_d, sizeof(projective_t)); // Print the result std::cout << projective_t::to_affine(result) << std::endl; // Free the device memory icicle_free(scalars_d); icicle_free(points_d); icicle_free(result_d); } std::cout << "\nPart II: use G2 points" << std::endl; std::cout << "Generating random inputs on-host" << std::endl; // use the same scalars auto g2_points = std::make_unique(N); g2_projective_t::rand_host_many(g2_points.get(), N); std::cout << "Reconfiguring MSM to use on-host inputs" << std::endl; config.are_results_on_device = false; config.are_scalars_on_device = false; config.are_points_on_device = false; g2_projective_t g2_result; START_TIMER(MSM_g2); ICICLE_CHECK(bn254_g2_msm(scalars.get(), g2_points.get(), msm_size, config, &g2_result)); END_TIMER(MSM_g2, "MSM G2 from host-memory took"); std::cout << g2_projective_t::to_affine(g2_result) << std::endl; // Similar to G1 MSM, can explicitly copy to device and execute the G2 MSM using device pointers return 0; }