FEAT(stark252 field): Adds Stark252 curve (#494)

## Describe the changes

Adds support for the stark252 base field.
This commit is contained in:
PatStiles
2024-05-01 08:08:05 -03:00
committed by GitHub
parent 36e288c1fa
commit bdc3da98d6
15 changed files with 860 additions and 5 deletions

View File

@@ -9,6 +9,7 @@ members = [
"icicle-curves/icicle-bn254",
"icicle-curves/icicle-grumpkin",
"icicle-fields/icicle-babybear",
"icicle-fields/icicle-stark252",
"icicle-hash",
]
exclude = [

View File

@@ -0,0 +1,22 @@
[package]
name = "icicle-stark252"
version.workspace = true
edition.workspace = true
authors.workspace = true
description = "Rust wrapper for the CUDA implementation of stark252 prime field by Ingonyama"
homepage.workspace = true
repository.workspace = true
[dependencies]
icicle-core = { workspace = true }
icicle-cuda-runtime = { workspace = true }
[build-dependencies]
cmake = "0.1.50"
[dev-dependencies]
lambdaworks-math = "0.6.0"
[features]
default = []
devmode = ["icicle-core/devmode"]

View File

@@ -0,0 +1,24 @@
use cmake::Config;
fn main() {
println!("cargo:rerun-if-env-changed=CXXFLAGS");
println!("cargo:rerun-if-changed=../../../../icicle");
// Base config
let mut config = Config::new("../../../../icicle/");
config
.define("FIELD", "stark252")
.define("CMAKE_BUILD_TYPE", "Release")
.define("EXT_FIELD", "OFF");
// Build
let out_dir = config
.build_target("icicle_field")
.build();
println!("cargo:rustc-link-search={}/build/lib", out_dir.display());
println!("cargo:rustc-link-lib=ingo_field_stark252");
println!("cargo:rustc-link-lib=stdc++");
println!("cargo:rustc-link-lib=cudart");
}

View File

@@ -0,0 +1,19 @@
use icicle_core::field::{Field, MontgomeryConvertibleField};
use icicle_core::traits::{FieldConfig, FieldImpl, GenerateRandom};
use icicle_core::{impl_field, impl_scalar_field};
use icicle_cuda_runtime::device::check_device;
use icicle_cuda_runtime::device_context::DeviceContext;
use icicle_cuda_runtime::error::CudaError;
use icicle_cuda_runtime::memory::{DeviceSlice, HostOrDeviceSlice};
pub(crate) const SCALAR_LIMBS: usize = 8;
impl_scalar_field!("stark252", stark252, SCALAR_LIMBS, ScalarField, ScalarCfg, Fr);
#[cfg(test)]
mod tests {
use super::ScalarField;
use icicle_core::impl_field_tests;
use icicle_core::tests::*;
impl_field_tests!(ScalarField);
}

View File

@@ -0,0 +1,4 @@
pub mod field;
pub mod ntt;
pub mod polynomials;
pub mod vec_ops;

View File

@@ -0,0 +1,60 @@
use crate::field::{ScalarCfg, ScalarField};
use icicle_core::error::IcicleResult;
use icicle_core::ntt::{NTTConfig, NTTDir, NTTDomain, NTT};
use icicle_core::traits::IcicleResultWrap;
use icicle_core::{impl_ntt, impl_ntt_without_domain};
use icicle_cuda_runtime::device_context::DeviceContext;
use icicle_cuda_runtime::error::CudaError;
use icicle_cuda_runtime::memory::HostOrDeviceSlice;
impl_ntt!("stark252", stark252, ScalarField, ScalarCfg);
#[cfg(test)]
pub(crate) mod tests {
use super::ScalarField;
use icicle_core::{
ntt::{initialize_domain, ntt_inplace, NTTConfig, NTTDir},
traits::{FieldImpl, GenerateRandom},
};
use icicle_cuda_runtime::{device_context::DeviceContext, memory::HostSlice};
use lambdaworks_math::{
field::{
element::FieldElement, fields::fft_friendly::stark_252_prime_field::Stark252PrimeField, traits::IsFFTField,
},
polynomial::Polynomial,
traits::ByteConversion,
};
pub type FE = FieldElement<Stark252PrimeField>;
#[test]
fn test_against_lambdaworks() {
let log_sizes = [15, 20];
let ctx = DeviceContext::default();
let lw_root_of_unity = Stark252PrimeField::get_primitive_root_of_unity(log_sizes[log_sizes.len() - 1]).unwrap();
initialize_domain(ScalarField::from_bytes_le(&lw_root_of_unity.to_bytes_le()), &ctx, false).unwrap();
for log_size in log_sizes {
let ntt_size = 1 << log_size;
let mut scalars: Vec<ScalarField> = <ScalarField as FieldImpl>::Config::generate_random(ntt_size);
let scalars_lw: Vec<FE> = scalars
.iter()
.map(|x| FieldElement::from_bytes_le(&x.to_bytes_le()).unwrap())
.collect();
let ntt_cfg: NTTConfig<'_, ScalarField> = NTTConfig::default();
ntt_inplace(HostSlice::from_mut_slice(&mut scalars[..]), NTTDir::kForward, &ntt_cfg).unwrap();
let poly = Polynomial::new(&scalars_lw[..]);
let evaluations = Polynomial::evaluate_fft::<Stark252PrimeField>(&poly, 1, None).unwrap();
for (s1, s2) in scalars
.iter()
.zip(evaluations.iter())
{
assert_eq!(s1.to_bytes_le(), s2.to_bytes_le());
}
}
}
}

View File

@@ -0,0 +1,10 @@
use crate::field::{ScalarCfg, ScalarField};
use icicle_core::impl_univariate_polynomial_api;
impl_univariate_polynomial_api!("stark252", stark252, ScalarField, ScalarCfg);
#[cfg(test)]
mod tests {
use icicle_core::impl_polynomial_tests;
impl_polynomial_tests!(stark252, ScalarField);
}

View File

@@ -0,0 +1,20 @@
use crate::field::{ScalarCfg, ScalarField};
use icicle_core::error::IcicleResult;
use icicle_core::impl_vec_ops_field;
use icicle_core::traits::IcicleResultWrap;
use icicle_core::vec_ops::{VecOps, VecOpsConfig};
use icicle_cuda_runtime::device_context::DeviceContext;
use icicle_cuda_runtime::error::CudaError;
use icicle_cuda_runtime::memory::HostOrDeviceSlice;
impl_vec_ops_field!("stark252", stark252, ScalarField, ScalarCfg);
#[cfg(test)]
pub(crate) mod tests {
use crate::field::ScalarField;
use icicle_core::impl_vec_add_tests;
use icicle_core::vec_ops::tests::*;
impl_vec_add_tests!(ScalarField);
}