From eb89a9a469e8021db8e4a1f2774ce70466e76190 Mon Sep 17 00:00:00 2001 From: Yuval Shekel Date: Wed, 26 Jun 2024 13:24:01 +0300 Subject: [PATCH] bn254 curve crate --- icicle_v3/cmake/curve.cmake | 2 +- .../icicle/curves/montgomery_conversion.h | 8 +- .../src/curves/montgomery_conversion.cpp | 12 +- wrappers/rust_v3/Cargo.toml | 1 + wrappers/rust_v3/icicle-core/Cargo.toml | 4 + wrappers/rust_v3/icicle-core/src/curve.rs | 333 ++++++++++++++++++ wrappers/rust_v3/icicle-core/src/field.rs | 29 +- wrappers/rust_v3/icicle-core/src/lib.rs | 1 + .../rust_v3/icicle-core/src/test_utilities.rs | 4 - wrappers/rust_v3/icicle-core/src/tests.rs | 171 +++++---- .../rust_v3/icicle-core/src/vec_ops/mod.rs | 64 ++-- .../rust_v3/icicle-core/src/vec_ops/tests.rs | 11 +- .../icicle-curves/icicle-bn254/Cargo.toml | 26 ++ .../icicle-curves/icicle-bn254/build.rs | 54 +++ .../icicle-curves/icicle-bn254/src/curve.rs | 54 +++ .../icicle-curves/icicle-bn254/src/lib.rs | 3 + .../icicle-curves/icicle-bn254/src/ntt/mod.rs | 18 + .../icicle-bn254/src/vec_ops/mod.rs | 16 + 18 files changed, 658 insertions(+), 153 deletions(-) create mode 100644 wrappers/rust_v3/icicle-core/src/curve.rs create mode 100644 wrappers/rust_v3/icicle-curves/icicle-bn254/Cargo.toml create mode 100644 wrappers/rust_v3/icicle-curves/icicle-bn254/build.rs create mode 100644 wrappers/rust_v3/icicle-curves/icicle-bn254/src/curve.rs create mode 100644 wrappers/rust_v3/icicle-curves/icicle-bn254/src/lib.rs create mode 100644 wrappers/rust_v3/icicle-curves/icicle-bn254/src/ntt/mod.rs create mode 100644 wrappers/rust_v3/icicle-curves/icicle-bn254/src/vec_ops/mod.rs diff --git a/icicle_v3/cmake/curve.cmake b/icicle_v3/cmake/curve.cmake index ed5ef1f547..6936b4ea7f 100644 --- a/icicle_v3/cmake/curve.cmake +++ b/icicle_v3/cmake/curve.cmake @@ -26,7 +26,7 @@ function(setup_curve_target) src/curves/ffi_extern.cpp src/curves/montgomery_conversion.cpp ) - target_link_libraries(icicle_curve PUBLIC icicle_device icicle_field) + target_link_libraries(icicle_curve PUBLIC icicle_device icicle_field) set_target_properties(icicle_curve PROPERTIES OUTPUT_NAME "icicle_curve_${CURVE}") # Make sure CURVE is defined in the cache for backends to see diff --git a/icicle_v3/include/icicle/curves/montgomery_conversion.h b/icicle_v3/include/icicle/curves/montgomery_conversion.h index 9772b8e25b..9d5e9d1eb0 100644 --- a/icicle_v3/include/icicle/curves/montgomery_conversion.h +++ b/icicle_v3/include/icicle/curves/montgomery_conversion.h @@ -59,12 +59,12 @@ namespace icicle { const VecOpsConfig& config, g2_affine_t* output)>; - void register_affine_g2_convert_montgomery(const std::string& deviceType, AffineG2ConvertMontImpl); + void register_g2_affine_convert_montgomery(const std::string& deviceType, AffineG2ConvertMontImpl); #define REGISTER_AFFINE_G2_CONVERT_MONTGOMERY_BACKEND(DEVICE_TYPE, FUNC) \ namespace { \ static bool UNIQUE(_reg_affine_g2_convert_mont) = []() -> bool { \ - register_affine_g2_convert_montgomery(DEVICE_TYPE, FUNC); \ + register_g2_affine_convert_montgomery(DEVICE_TYPE, FUNC); \ return true; \ }(); \ } @@ -77,12 +77,12 @@ namespace icicle { const VecOpsConfig& config, g2_projective_t* output)>; - void register_projective_g2_convert_montgomery(const std::string& deviceType, ProjectiveG2ConvertMontImpl); + void register_g2_projective_convert_montgomery(const std::string& deviceType, ProjectiveG2ConvertMontImpl); #define REGISTER_PROJECTIVE_G2_CONVERT_MONTGOMERY_BACKEND(DEVICE_TYPE, FUNC) \ namespace { \ static bool UNIQUE(_reg_projective_g2_convert_mont) = []() -> bool { \ - register_projective_g2_convert_montgomery(DEVICE_TYPE, FUNC); \ + register_g2_projective_convert_montgomery(DEVICE_TYPE, FUNC); \ return true; \ }(); \ } diff --git a/icicle_v3/src/curves/montgomery_conversion.cpp b/icicle_v3/src/curves/montgomery_conversion.cpp index 59f19bb364..bfe1f12eb9 100644 --- a/icicle_v3/src/curves/montgomery_conversion.cpp +++ b/icicle_v3/src/curves/montgomery_conversion.cpp @@ -24,9 +24,9 @@ namespace icicle { } #ifdef G2 - ICICLE_DISPATCHER_INST(AffineG2ConvertMont, affine_g2_convert_montgomery, AffineG2ConvertMontImpl); + ICICLE_DISPATCHER_INST(AffineG2ConvertMont, g2_affine_convert_montgomery, AffineG2ConvertMontImpl); - extern "C" eIcicleError CONCAT_EXPAND(CURVE, affine_g2_convert_montgomery)( + extern "C" eIcicleError CONCAT_EXPAND(CURVE, g2_affine_convert_montgomery)( const g2_affine_t* input, size_t n, bool is_into, const VecOpsConfig& config, g2_affine_t* output) { return AffineG2ConvertMont::execute(input, n, is_into, config, output); @@ -37,7 +37,7 @@ namespace icicle { eIcicleError convert_montgomery(const g2_affine_t* input, size_t n, bool is_into, const VecOpsConfig& config, g2_affine_t* output) { - return CONCAT_EXPAND(CURVE, affine_g2_convert_montgomery)(input, n, is_into, config, output); + return CONCAT_EXPAND(CURVE, g2_affine_convert_montgomery)(input, n, is_into, config, output); } #endif //! G1_AFFINE_SAME_TYPE_AS_G2_AFFINE #endif // G2 @@ -58,9 +58,9 @@ namespace icicle { } #ifdef G2 - ICICLE_DISPATCHER_INST(ProjectiveG2ConvertMont, projective_g2_convert_montgomery, ProjectiveG2ConvertMontImpl); + ICICLE_DISPATCHER_INST(ProjectiveG2ConvertMont, g2_projective_convert_montgomery, ProjectiveG2ConvertMontImpl); - extern "C" eIcicleError CONCAT_EXPAND(CURVE, projective_g2_convert_montgomery)( + extern "C" eIcicleError CONCAT_EXPAND(CURVE, g2_projective_convert_montgomery)( const g2_projective_t* input, uint64_t n, bool is_into, const VecOpsConfig& config, g2_projective_t* output) { return ProjectiveG2ConvertMont::execute(input, n, is_into, config, output); @@ -70,7 +70,7 @@ namespace icicle { eIcicleError convert_montgomery( const g2_projective_t* input, uint64_t n, bool is_into, const VecOpsConfig& config, g2_projective_t* output) { - return CONCAT_EXPAND(CURVE, projective_g2_convert_montgomery)(input, n, is_into, config, output); + return CONCAT_EXPAND(CURVE, g2_projective_convert_montgomery)(input, n, is_into, config, output); } #endif // G2 diff --git a/wrappers/rust_v3/Cargo.toml b/wrappers/rust_v3/Cargo.toml index dd0ef50502..62a3ad6a18 100644 --- a/wrappers/rust_v3/Cargo.toml +++ b/wrappers/rust_v3/Cargo.toml @@ -5,6 +5,7 @@ members = [ "icicle-core", "icicle-fields/icicle-babybear", "icicle-fields/icicle-stark252", + "icicle-curves/icicle-bn254", ] exclude = [] diff --git a/wrappers/rust_v3/icicle-core/Cargo.toml b/wrappers/rust_v3/icicle-core/Cargo.toml index e200be0356..57f8026cda 100644 --- a/wrappers/rust_v3/icicle-core/Cargo.toml +++ b/wrappers/rust_v3/icicle-core/Cargo.toml @@ -16,3 +16,7 @@ rayon = "1.8.1" criterion = "0.3" serial_test = "3.0.0" once_cell = "1.10.0" + +[features] +g2 = [] +ec_ntt = [] diff --git a/wrappers/rust_v3/icicle-core/src/curve.rs b/wrappers/rust_v3/icicle-core/src/curve.rs new file mode 100644 index 0000000000..a7e8bdc9ee --- /dev/null +++ b/wrappers/rust_v3/icicle-core/src/curve.rs @@ -0,0 +1,333 @@ +use crate::traits::{FieldImpl, MontgomeryConvertible}; +use icicle_runtime::{ + errors::eIcicleError, + memory::{DeviceSlice, HostOrDeviceSlice}, + stream::IcicleStream, +}; +use std::fmt::Debug; + +pub trait Curve: Debug + PartialEq + Copy + Clone { + type BaseField: FieldImpl; + type ScalarField: FieldImpl; + + #[doc(hidden)] + fn eq_proj(point1: *const Projective, point2: *const Projective) -> bool; + #[doc(hidden)] + fn to_affine(point: *const Projective, point_aff: *mut Affine); + #[doc(hidden)] + fn generate_random_projective_points(size: usize) -> Vec>; + #[doc(hidden)] + fn generate_random_affine_points(size: usize) -> Vec>; + #[doc(hidden)] + fn convert_affine_montgomery(points: *mut Affine, len: usize, is_into: bool, stream: &IcicleStream) -> eIcicleError; + #[doc(hidden)] + fn convert_projective_montgomery(points: *mut Projective, len: usize, is_into: bool, stream: &IcicleStream) -> eIcicleError; +} + +/// A [projective](https://hyperelliptic.org/EFD/g1p/auto-shortw-projective.html) elliptic curve point. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct Projective { + pub x: C::BaseField, + pub y: C::BaseField, + pub z: C::BaseField, +} + +/// An [affine](https://hyperelliptic.org/EFD/g1p/auto-shortw.html) elliptic curve point. +#[derive(Debug, PartialEq, Clone, Copy)] +#[repr(C)] +pub struct Affine { + pub x: C::BaseField, + pub y: C::BaseField, +} + +impl Affine { + // While this is not a true zero point and not even a valid point, it's still useful + // both as a handy default as well as a representation of zero points in other codebases + pub fn zero() -> Self { + Affine { + x: C::BaseField::zero(), + y: C::BaseField::zero(), + } + } + + pub fn from_limbs(x: ::Repr, y: ::Repr) -> Self { + Affine { + x: C::BaseField::from(x), + y: C::BaseField::from(y), + } + } + + pub fn to_projective(&self) -> Projective { + Projective { + x: self.x, + y: self.y, + z: C::BaseField::one(), + } + } +} + +impl From> for Projective { + fn from(item: Affine) -> Self { + if item == (Affine::::zero()) { + return Self::zero(); + } + Self { + x: item.x, + y: item.y, + z: C::BaseField::one(), + } + } +} + +impl Projective { + pub fn zero() -> Self { + Projective { + x: C::BaseField::zero(), + y: C::BaseField::one(), + z: C::BaseField::zero(), + } + } + + pub fn from_limbs( + x: ::Repr, + y: ::Repr, + z: ::Repr, + ) -> Self { + Projective { + x: C::BaseField::from(x), + y: C::BaseField::from(y), + z: C::BaseField::from(z), + } + } +} + +impl PartialEq for Projective { + fn eq(&self, other: &Self) -> bool { + C::eq_proj(self as *const Self, other as *const Self) + } +} + +impl From> for Affine { + fn from(proj: Projective) -> Self { + let mut aff = Self::zero(); + C::to_affine(&proj as *const Projective, &mut aff as *mut Self); + aff + } +} + +impl MontgomeryConvertible for Affine { + fn to_mont(values: &mut DeviceSlice, stream: &IcicleStream) -> eIcicleError { + // TODO Yuval : check device + // check_device(ctx.device_id); + // assert_eq!( + // values + // .device_id() + // .unwrap(), + // ctx.device_id, + // "Device ids are different in slice and context" + // ); + C::convert_affine_montgomery(unsafe { values.as_mut_ptr() }, values.len(), true, stream) + } + + fn from_mont(values: &mut DeviceSlice, stream: &IcicleStream) -> eIcicleError { + // TODO Yuval : check device + // check_device(ctx.device_id); + // assert_eq!( + // values + // .device_id() + // .unwrap(), + // ctx.device_id, + // "Device ids are different in slice and context" + // ); + C::convert_affine_montgomery(unsafe { values.as_mut_ptr() }, values.len(), false, stream) + } +} + +impl MontgomeryConvertible for Projective { + fn to_mont(values: &mut DeviceSlice, stream: &IcicleStream) -> eIcicleError { + // TODO Yuval : check device + // check_device(ctx.device_id); + // assert_eq!( + // values + // .device_id() + // .unwrap(), + // ctx.device_id, + // "Device ids are different in slice and context" + // ); + C::convert_projective_montgomery(unsafe { values.as_mut_ptr() }, values.len(), true, stream) + } + + fn from_mont(values: &mut DeviceSlice, stream: &IcicleStream) -> eIcicleError { + // TODO Yuval : check device + // check_device(ctx.device_id); + // assert_eq!( + // values + // .device_id() + // .unwrap(), + // ctx.device_id, + // "Device ids are different in slice and context" + // ); + C::convert_projective_montgomery(unsafe { values.as_mut_ptr() }, values.len(), false, stream) + } +} + +#[macro_export] +macro_rules! impl_curve { + ( + $curve_prefix:literal, + $curve_prefix_ident:ident, + $curve:ident, + $scalar_field:ident, + $base_field:ident, + $affine_type:ident, + $projective_type:ident + ) => { + #[derive(Debug, PartialEq, Copy, Clone)] + pub struct $curve {} + + pub type $affine_type = Affine<$curve>; + pub type $projective_type = Projective<$curve>; + + mod $curve_prefix_ident { + use super::{eIcicleError, $affine_type, $projective_type, IcicleStream, VecOpsConfig}; + + extern "C" { + #[link_name = concat!($curve_prefix, "_eq")] + pub(crate) fn eq(point1: *const $projective_type, point2: *const $projective_type) -> bool; + #[link_name = concat!($curve_prefix, "_to_affine")] + pub(crate) fn proj_to_affine(point: *const $projective_type, point_out: *mut $affine_type); + #[link_name = concat!($curve_prefix, "_generate_projective_points")] + pub(crate) fn generate_projective_points(points: *mut $projective_type, size: usize); + #[link_name = concat!($curve_prefix, "_generate_affine_points")] + pub(crate) fn generate_affine_points(points: *mut $affine_type, size: usize); + #[link_name = concat!($curve_prefix, "_affine_convert_montgomery")] + pub(crate) fn _convert_affine_montgomery( + input: *const $affine_type, + size: usize, + is_into: bool, + config: &VecOpsConfig, + output: *mut $affine_type, + ) -> eIcicleError; + #[link_name = concat!($curve_prefix, "_projective_convert_montgomery")] + pub(crate) fn _convert_projective_montgomery( + input: *const $projective_type, + size: usize, + is_into: bool, + config: &VecOpsConfig, + output: *mut $projective_type, + ) -> eIcicleError; + } + } + + impl Curve for $curve { + type BaseField = $base_field; + type ScalarField = $scalar_field; + + fn eq_proj(point1: *const $projective_type, point2: *const $projective_type) -> bool { + unsafe { $curve_prefix_ident::eq(point1, point2) } + } + + fn to_affine(point: *const $projective_type, point_out: *mut $affine_type) { + unsafe { $curve_prefix_ident::proj_to_affine(point, point_out) }; + } + + fn generate_random_projective_points(size: usize) -> Vec<$projective_type> { + let mut res = vec![$projective_type::zero(); size]; + unsafe { + $curve_prefix_ident::generate_projective_points( + &mut res[..] as *mut _ as *mut $projective_type, + size, + ) + }; + res + } + + fn generate_random_affine_points(size: usize) -> Vec<$affine_type> { + let mut res = vec![$affine_type::zero(); size]; + unsafe { + $curve_prefix_ident::generate_affine_points(&mut res[..] as *mut _ as *mut $affine_type, size) + }; + res + } + + fn convert_affine_montgomery( + points: *mut $affine_type, + len: usize, + is_into: bool, + stream: &IcicleStream, + ) -> eIcicleError { + let mut config = VecOpsConfig::default(); + config.is_a_on_device = true; + config.is_result_on_device = true; + config.is_async = false; + config.stream_handle = (&*stream).into(); + unsafe { + $curve_prefix_ident::_convert_affine_montgomery( + points, + len, + is_into, + &config, + points + ) + } + } + + fn convert_projective_montgomery( + points: *mut $projective_type, + len: usize, + is_into: bool, + stream: &IcicleStream, + ) -> eIcicleError { + let mut config = VecOpsConfig::default(); + config.is_a_on_device = true; + config.is_result_on_device = true; + config.is_async = false; + config.stream_handle = (&*stream).into(); + unsafe { + $curve_prefix_ident::_convert_projective_montgomery( + points, + len, + is_into, + &config, + points + ) + } + } + } + }; +} + +#[macro_export] +macro_rules! impl_curve_tests { + ( + $base_limbs:ident, + $curve:ident + ) => { + pub mod test_curve { + use super::*; + fn initialize() { + test_utilities::test_load_and_init_devices(); + test_utilities::test_set_main_device(); + } + + #[test] + fn test_affine_projective_convert() { + initialize(); + check_affine_projective_convert::<$curve>() + } + + #[test] + fn test_point_equality() { + initialize(); + check_point_equality::<$base_limbs, <<$curve as Curve>::BaseField as FieldImpl>::Config, $curve>() + } + + #[test] + fn test_points_convert_montgomery() { + initialize(); + check_points_convert_montgomery::<$curve>() + } + } + }; +} \ No newline at end of file diff --git a/wrappers/rust_v3/icicle-core/src/field.rs b/wrappers/rust_v3/icicle-core/src/field.rs index 1866c72a55..6dd9013700 100644 --- a/wrappers/rust_v3/icicle-core/src/field.rs +++ b/wrappers/rust_v3/icicle-core/src/field.rs @@ -1,5 +1,4 @@ use crate::traits::{FieldConfig, FieldImpl, MontgomeryConvertible}; -// use crate::vec_ops::VecOpsConfig; use hex::FromHex; use icicle_runtime::errors::eIcicleError; use icicle_runtime::memory::DeviceSlice; @@ -176,7 +175,7 @@ macro_rules! impl_scalar_field { let mut config = VecOpsConfig::default(); config.is_a_on_device = true; config.is_result_on_device = true; - config.is_async = !stream.is_null(); + config.is_async = false; config.stream_handle = (&*stream).into(); unsafe { _convert_scalars_montgomery(scalars, len as u64, is_into, &config, scalars) } } @@ -233,14 +232,26 @@ macro_rules! impl_field_tests { ( $field_name:ident ) => { - #[test] - fn test_field_convert_montgomery() { - check_field_convert_montgomery::<$field_name>() - } + pub mod test_field { + use super::*; + use icicle_core::test_utilities; + + fn initialize() { + test_utilities::test_load_and_init_devices(); + test_utilities::test_set_main_device(); + } - #[test] - fn test_field_equality() { - check_field_equality::<$field_name>() + #[test] + fn test_field_convert_montgomery() { + initialize(); + check_field_convert_montgomery::<$field_name>() + } + + #[test] + fn test_field_equality() { + initialize(); + check_field_equality::<$field_name>() + } } }; } diff --git a/wrappers/rust_v3/icicle-core/src/lib.rs b/wrappers/rust_v3/icicle-core/src/lib.rs index 5577f78984..ffc894c6f3 100644 --- a/wrappers/rust_v3/icicle-core/src/lib.rs +++ b/wrappers/rust_v3/icicle-core/src/lib.rs @@ -1,3 +1,4 @@ +pub mod curve; pub mod field; pub mod ntt; pub mod vec_ops; diff --git a/wrappers/rust_v3/icicle-core/src/test_utilities.rs b/wrappers/rust_v3/icicle-core/src/test_utilities.rs index 42071f00f7..19325e4de0 100644 --- a/wrappers/rust_v3/icicle-core/src/test_utilities.rs +++ b/wrappers/rust_v3/icicle-core/src/test_utilities.rs @@ -10,11 +10,7 @@ pub static TEST_REF_DEVICE: Lazy> = Lazy::new(|| Mutex::new(Device pub fn test_load_and_init_devices() { INIT.get_or_init(move || { - // let default_backend_install_dir = env!("DEFAULT_BACKEND_INSTALL_DIR"); runtime::load_backend(env!("DEFAULT_BACKEND_INSTALL_DIR"), true).unwrap(); - // runtime::load_backend(&format!("{}/cuda", default_backend_install_dir), true).unwrap(); - // runtime::load_backend(&format!("{}/babybear", default_backend_install_dir), true).unwrap(); - // runtime::load_backend(&format!("{}/stark252", default_backend_install_dir), true).unwrap(); let registered_devices = runtime::get_registered_devices().unwrap(); assert!(registered_devices.len() >= 2); // select main and ref devices diff --git a/wrappers/rust_v3/icicle-core/src/tests.rs b/wrappers/rust_v3/icicle-core/src/tests.rs index 19a349bb45..20d8b6d036 100644 --- a/wrappers/rust_v3/icicle-core/src/tests.rs +++ b/wrappers/rust_v3/icicle-core/src/tests.rs @@ -1,4 +1,8 @@ -use crate::traits::{FieldImpl, GenerateRandom, MontgomeryConvertible}; +use crate::{ + curve::{Affine, Curve, Projective}, + field::Field, + traits::{FieldConfig, FieldImpl, GenerateRandom, MontgomeryConvertible}, +}; use icicle_runtime::{ memory::{DeviceVec, HostSlice}, stream::IcicleStream, @@ -12,36 +16,36 @@ pub fn check_field_equality() { assert_eq!(left, right); } -// pub fn check_affine_projective_convert() { -// let size = 1 << 10; -// let affine_points = C::generate_random_affine_points(size); -// let projective_points = C::generate_random_projective_points(size); -// for affine_point in affine_points { -// let projective_eqivalent: Projective = affine_point.into(); -// assert_eq!(affine_point, projective_eqivalent.into()); -// } -// for projective_point in projective_points { -// let affine_eqivalent: Affine = projective_point.into(); -// assert_eq!(projective_point, affine_eqivalent.into()); -// } -// } - -// pub fn check_point_equality() -// where -// C: Curve>, -// { -// let left = Projective::::zero(); -// let right = Projective::::zero(); -// assert_eq!(left, right); -// let right = Projective::::from_limbs([0; BASE_LIMBS], [2; BASE_LIMBS], [0; BASE_LIMBS]); -// assert_eq!(left, right); -// let mut z = [0; BASE_LIMBS]; -// z[0] = 2; -// let right = Projective::::from_limbs([0; BASE_LIMBS], [4; BASE_LIMBS], z); -// assert_ne!(left, right); -// let left = Projective::::from_limbs([0; BASE_LIMBS], [2; BASE_LIMBS], C::BaseField::one().into()); -// assert_eq!(left, right); -// } +pub fn check_affine_projective_convert() { + let size = 1 << 10; + let affine_points = C::generate_random_affine_points(size); + let projective_points = C::generate_random_projective_points(size); + for affine_point in affine_points { + let projective_eqivalent: Projective = affine_point.into(); + assert_eq!(affine_point, projective_eqivalent.into()); + } + for projective_point in projective_points { + let affine_eqivalent: Affine = projective_point.into(); + assert_eq!(projective_point, affine_eqivalent.into()); + } +} + +pub fn check_point_equality() +where + C: Curve>, +{ + let left = Projective::::zero(); + let right = Projective::::zero(); + assert_eq!(left, right); + let right = Projective::::from_limbs([0; BASE_LIMBS], [2; BASE_LIMBS], [0; BASE_LIMBS]); + assert_eq!(left, right); + let mut z = [0; BASE_LIMBS]; + z[0] = 2; + let right = Projective::::from_limbs([0; BASE_LIMBS], [4; BASE_LIMBS], z); + assert_ne!(left, right); + let left = Projective::::from_limbs([0; BASE_LIMBS], [2; BASE_LIMBS], C::BaseField::one().into()); + assert_eq!(left, right); +} pub fn check_field_convert_montgomery() where @@ -75,61 +79,50 @@ where assert_eq!(scalars_copy, scalars); } -// pub fn check_points_convert_montgomery() -// where -// Affine: MontgomeryConvertible<'static>, -// Projective: MontgomeryConvertible<'static>, -// { -// let size = 1 << 10; -// let device_ctx = DeviceContext::default(); - -// let affine_points = C::generate_random_affine_points(size); -// let mut d_affine = DeviceVec::cuda_malloc(size).unwrap(); -// d_affine -// .copy_from_host(HostSlice::from_slice(&affine_points)) -// .unwrap(); - -// Affine::::to_mont(&mut d_affine, &device_ctx) -// .wrap() -// .unwrap(); -// Affine::::from_mont(&mut d_affine, &device_ctx) -// .wrap() -// .unwrap(); - -// let mut affine_copy = vec![Affine::::zero(); size]; -// d_affine -// .copy_to_host(HostSlice::from_mut_slice(&mut affine_copy)) -// .unwrap(); - -// for (p1, p2) in affine_points -// .iter() -// .zip(affine_copy.iter()) -// { -// assert_eq!(p1, p2); -// } - -// let proj_points = C::generate_random_projective_points(size); -// let mut d_proj = DeviceVec::cuda_malloc(size).unwrap(); -// d_proj -// .copy_from_host(HostSlice::from_slice(&proj_points)) -// .unwrap(); - -// Projective::::to_mont(&mut d_proj, &device_ctx) -// .wrap() -// .unwrap(); -// Projective::::from_mont(&mut d_proj, &device_ctx) -// .wrap() -// .unwrap(); - -// let mut projective_copy = vec![Projective::::zero(); size]; -// d_proj -// .copy_to_host(HostSlice::from_mut_slice(&mut projective_copy)) -// .unwrap(); - -// for (p1, p2) in proj_points -// .iter() -// .zip(projective_copy.iter()) -// { -// assert_eq!(p1, p2); -// } -// } +pub fn check_points_convert_montgomery() +where + Affine: MontgomeryConvertible, + Projective: MontgomeryConvertible, +{ + let size = 1 << 10; + + let affine_points = C::generate_random_affine_points(size); + let mut d_affine = DeviceVec::device_malloc(size).unwrap(); + d_affine + .copy_from_host(HostSlice::from_slice(&affine_points)) + .unwrap(); + + Affine::::to_mont(&mut d_affine, &IcicleStream::default()) + .wrap() + .unwrap(); + Affine::::from_mont(&mut d_affine, &IcicleStream::default()) + .wrap() + .unwrap(); + + let mut affine_copy = vec![Affine::::zero(); size]; + d_affine + .copy_to_host(HostSlice::from_mut_slice(&mut affine_copy)) + .unwrap(); + + assert_eq!(affine_points, affine_copy); + + let proj_points = C::generate_random_projective_points(size); + let mut d_proj = DeviceVec::device_malloc(size).unwrap(); + d_proj + .copy_from_host(HostSlice::from_slice(&proj_points)) + .unwrap(); + + Projective::::to_mont(&mut d_proj, &IcicleStream::default()) + .wrap() + .unwrap(); + Projective::::from_mont(&mut d_proj, &IcicleStream::default()) + .wrap() + .unwrap(); + + let mut projective_copy = vec![Projective::::zero(); size]; + d_proj + .copy_to_host(HostSlice::from_mut_slice(&mut projective_copy)) + .unwrap(); + + assert_eq!(proj_points, projective_copy); +} diff --git a/wrappers/rust_v3/icicle-core/src/vec_ops/mod.rs b/wrappers/rust_v3/icicle-core/src/vec_ops/mod.rs index ae9fb08b0f..2b7d7624db 100644 --- a/wrappers/rust_v3/icicle-core/src/vec_ops/mod.rs +++ b/wrappers/rust_v3/icicle-core/src/vec_ops/mod.rs @@ -305,6 +305,8 @@ macro_rules! impl_vec_ops_field { } } + // TODO Yuval : implement bit reverse + // fn bit_reverse( // input: &(impl HostOrDeviceSlice<$field> + ?Sized), // cfg: &BitReverseConfig, @@ -344,44 +346,36 @@ macro_rules! impl_vec_ops_tests { ( $field:ident ) => { - use icicle_core::test_utilities; - use icicle_runtime::{device::Device, runtime}; - use std::sync::Once; + pub(crate) mod test_vecops { + use super::*; + use icicle_core::test_utilities; + use icicle_runtime::{device::Device, runtime}; + use std::sync::Once; + + fn initialize() { + test_utilities::test_load_and_init_devices(); + } - fn initialize() { - test_utilities::test_load_and_init_devices(); - } + #[test] + pub fn test_vec_ops_scalars() { + initialize(); + check_vec_ops_scalars::<$field>() + } - #[test] - pub fn test_vec_ops_scalars() { - initialize(); - check_vec_ops_scalars::<$field>( - &test_utilities::TEST_MAIN_DEVICE - .lock() - .unwrap(), - ) - } + #[test] + pub fn test_matrix_transpose() { + initialize(); + check_matrix_transpose::<$field>() + } - #[test] - pub fn test_matrix_transpose() { - initialize(); - check_matrix_transpose::<$field>( - &test_utilities::TEST_MAIN_DEVICE - .lock() - .unwrap(), - &test_utilities::TEST_REF_DEVICE - .lock() - .unwrap(), - ) + // #[test] + // pub fn test_bit_reverse() { + // check_bit_reverse::<$field>() + // } + // #[test] + // pub fn test_bit_reverse_inplace() { + // check_bit_reverse_inplace::<$field>() + // } } - - // #[test] - // pub fn test_bit_reverse() { - // check_bit_reverse::<$field>() - // } - // #[test] - // pub fn test_bit_reverse_inplace() { - // check_bit_reverse_inplace::<$field>() - // } }; } diff --git a/wrappers/rust_v3/icicle-core/src/vec_ops/tests.rs b/wrappers/rust_v3/icicle-core/src/vec_ops/tests.rs index 4a480a8c3d..e767235f1c 100644 --- a/wrappers/rust_v3/icicle-core/src/vec_ops/tests.rs +++ b/wrappers/rust_v3/icicle-core/src/vec_ops/tests.rs @@ -1,4 +1,5 @@ #![allow(unused_imports)] +use crate::test_utilities; use crate::traits::GenerateRandom; use crate::vec_ops::{add_scalars, mul_scalars, sub_scalars, transpose_matrix, FieldImpl, VecOps, VecOpsConfig}; use icicle_runtime::device::Device; @@ -31,11 +32,11 @@ fn test_vec_ops_config() { .unwrap(); } -pub fn check_vec_ops_scalars(device: &Device) +pub fn check_vec_ops_scalars() where ::Config: VecOps + GenerateRandom, { - runtime::set_device(device).unwrap(); + test_utilities::test_set_main_device(); let test_size = 1 << 14; let a = F::Config::generate_random(test_size); @@ -67,7 +68,7 @@ where .unwrap(); } -pub fn check_matrix_transpose(main_dev: &Device, ref_dev: &Device) +pub fn check_matrix_transpose() where ::Config: VecOps + GenerateRandom, { @@ -79,7 +80,7 @@ where let mut result_ref = vec![F::zero(); test_size]; let cfg = VecOpsConfig::default(); - runtime::set_device(&main_dev).unwrap(); + test_utilities::test_set_main_device(); transpose_matrix( HostSlice::from_slice(&input_matrix), r, @@ -89,7 +90,7 @@ where ) .unwrap(); - runtime::set_device(&ref_dev).unwrap(); + test_utilities::test_set_ref_device(); transpose_matrix( HostSlice::from_slice(&input_matrix), r, diff --git a/wrappers/rust_v3/icicle-curves/icicle-bn254/Cargo.toml b/wrappers/rust_v3/icicle-curves/icicle-bn254/Cargo.toml new file mode 100644 index 0000000000..bf3e96334f --- /dev/null +++ b/wrappers/rust_v3/icicle-curves/icicle-bn254/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "icicle-bn254" +version.workspace = true +edition.workspace = true +authors.workspace = true +description = "Rust wrapper for the CUDA implementation of BN254 pairing friendly elliptic curve by Ingonyama" +homepage.workspace = true +repository.workspace = true + +[dependencies] +icicle-core = { workspace = true } +icicle-runtime = { workspace = true } +# criterion = "0.3" + +[dev-dependencies] +criterion = "0.3" +serial_test = "3.0.0" + +[build-dependencies] +cmake = "0.1.50" + +[features] +default = [] +g2 = ["icicle-core/g2"] +# ec_ntt = ["icicle-core/ec_ntt"] + diff --git a/wrappers/rust_v3/icicle-curves/icicle-bn254/build.rs b/wrappers/rust_v3/icicle-curves/icicle-bn254/build.rs new file mode 100644 index 0000000000..e3b48974a3 --- /dev/null +++ b/wrappers/rust_v3/icicle-curves/icicle-bn254/build.rs @@ -0,0 +1,54 @@ +use cmake::Config; +use std::{env, path::PathBuf}; + +fn main() { + // Construct the path to the deps directory + let out_dir = env::var("OUT_DIR").expect("OUT_DIR is not set"); + let build_dir = PathBuf::from(format!("{}/../../../", &out_dir)); + let deps_dir = build_dir.join("deps"); + + // Construct the path to icicle source directory + let main_dir = env::current_dir().expect("Failed to get current directory"); + let icicle_src_dir = PathBuf::from(format!("{}/../../../../icicle_v3", main_dir.display())); + + println!("cargo:rerun-if-env-changed=CXXFLAGS"); + println!("cargo:rerun-if-changed={}", icicle_src_dir.display()); + + // Base config + let mut config = Config::new(format!("{}", icicle_src_dir.display())); + // Check if ICICLE_INSTALL_DIR is defined + let icicle_install_dir = if let Ok(dir) = env::var("ICICLE_INSTALL_DIR") { + PathBuf::from(dir) + } else { + // Define the default install directory to be under the build directory + PathBuf::from(format!("{}/icicle/", deps_dir.display())) + }; + config + .define("CURVE", "bn254") + .define("CMAKE_BUILD_TYPE", "Release") + .define("CMAKE_INSTALL_PREFIX", &icicle_install_dir); + + // Optional Features + #[cfg(feature = "g2")] + config.define("G2", "ON"); + + #[cfg(feature = "ec_ntt")] + config.define("ECNTT", "ON"); + + // Build + let _ = config + .build_target("install") + .build(); + + println!("cargo:rustc-link-search={}/lib", icicle_install_dir.display()); + println!("cargo:rustc-link-lib=icicle_field_bn254"); + println!("cargo:rustc-link-lib=icicle_curve_bn254"); + println!("cargo:rustc-link-lib=stdc++"); + println!("cargo:rustc-link-arg=-Wl,-rpath,{}/lib", icicle_install_dir.display()); // Add RPATH linker arguments + + // default backends dir + println!( + "cargo:rustc-env=DEFAULT_BACKEND_INSTALL_DIR={}/lib/backend", + icicle_install_dir.display() + ); +} diff --git a/wrappers/rust_v3/icicle-curves/icicle-bn254/src/curve.rs b/wrappers/rust_v3/icicle-curves/icicle-bn254/src/curve.rs new file mode 100644 index 0000000000..ec93a83383 --- /dev/null +++ b/wrappers/rust_v3/icicle-curves/icicle-bn254/src/curve.rs @@ -0,0 +1,54 @@ +use icicle_core::{ + curve::{Affine, Curve, Projective}, + field::{Field, MontgomeryConvertibleField}, + impl_curve, impl_field, impl_scalar_field, + traits::{FieldConfig, FieldImpl, GenerateRandom}, + vec_ops::VecOpsConfig, +}; +use icicle_runtime::{ + eIcicleError, + memory::{DeviceSlice, HostOrDeviceSlice}, + stream::IcicleStream, +}; + +pub(crate) const SCALAR_LIMBS: usize = 8; +pub(crate) const BASE_LIMBS: usize = 8; +#[cfg(feature = "g2")] +pub(crate) const G2_BASE_LIMBS: usize = 16; + +impl_scalar_field!("bn254", bn254_sf, SCALAR_LIMBS, ScalarField, ScalarCfg); +impl_field!(BASE_LIMBS, BaseField, BaseCfg); +impl_curve!("bn254", bn254, CurveCfg, ScalarField, BaseField, G1Affine, G1Projective); + +#[cfg(feature = "g2")] +impl_field!(G2_BASE_LIMBS, G2BaseField, G2BaseCfg); +#[cfg(feature = "g2")] +impl_curve!( + "bn254_g2", + bn254_g2, + G2CurveCfg, + ScalarField, + G2BaseField, + G2Affine, + G2Projective +); + +#[cfg(test)] +mod tests { + use super::{CurveCfg, ScalarField, BASE_LIMBS}; + #[cfg(feature = "g2")] + use super::{G2CurveCfg, G2_BASE_LIMBS}; + use icicle_core::curve::Curve; + use icicle_core::test_utilities; + use icicle_core::tests::*; + use icicle_core::traits::FieldImpl; + use icicle_core::{impl_curve_tests, impl_field_tests}; + + impl_field_tests!(ScalarField); + impl_curve_tests!(BASE_LIMBS, CurveCfg); + #[cfg(feature = "g2")] + mod g2 { + use super::*; + impl_curve_tests!(G2_BASE_LIMBS, G2CurveCfg); + } +} diff --git a/wrappers/rust_v3/icicle-curves/icicle-bn254/src/lib.rs b/wrappers/rust_v3/icicle-curves/icicle-bn254/src/lib.rs new file mode 100644 index 0000000000..1bc241334d --- /dev/null +++ b/wrappers/rust_v3/icicle-curves/icicle-bn254/src/lib.rs @@ -0,0 +1,3 @@ +pub mod curve; +pub mod ntt; +pub mod vec_ops; diff --git a/wrappers/rust_v3/icicle-curves/icicle-bn254/src/ntt/mod.rs b/wrappers/rust_v3/icicle-curves/icicle-bn254/src/ntt/mod.rs new file mode 100644 index 0000000000..9cfebd00ba --- /dev/null +++ b/wrappers/rust_v3/icicle-curves/icicle-bn254/src/ntt/mod.rs @@ -0,0 +1,18 @@ +use crate::curve::{ScalarCfg, ScalarField}; + +use icicle_core::ntt::{NTTConfig, NTTDir, NTTDomain, NTTInitDomainConfig, NTT}; +use icicle_core::{impl_ntt, impl_ntt_without_domain}; +use icicle_runtime::{errors::eIcicleError, memory::HostOrDeviceSlice}; + +impl_ntt!("bn254", bn254, ScalarField, ScalarCfg); + +#[cfg(test)] +pub(crate) mod tests { + use crate::curve::ScalarField; + use icicle_core::impl_ntt_tests; + use icicle_core::ntt::tests::*; + use serial_test::{parallel, serial}; + use std::sync::OnceLock; + + impl_ntt_tests!(ScalarField); +} diff --git a/wrappers/rust_v3/icicle-curves/icicle-bn254/src/vec_ops/mod.rs b/wrappers/rust_v3/icicle-curves/icicle-bn254/src/vec_ops/mod.rs new file mode 100644 index 0000000000..4315cbcd00 --- /dev/null +++ b/wrappers/rust_v3/icicle-curves/icicle-bn254/src/vec_ops/mod.rs @@ -0,0 +1,16 @@ +use crate::curve::{ScalarCfg, ScalarField}; +use icicle_core::{ + impl_vec_ops_field, + vec_ops::{/*BitReverseConfig,*/ VecOps, VecOpsConfig}, +}; +use icicle_runtime::{errors::eIcicleError, memory::HostOrDeviceSlice}; + +impl_vec_ops_field!("bn254", bn254, ScalarField, ScalarCfg); +#[cfg(test)] +pub(crate) mod tests { + use crate::curve::ScalarField; + use icicle_core::impl_vec_ops_tests; + use icicle_core::vec_ops::tests::*; + + impl_vec_ops_tests!(ScalarField); +}