Skip to content

Commit

Permalink
FEAT(stark252 field): Adds Stark252 curve (#494)
Browse files Browse the repository at this point in the history
## Describe the changes

Adds support for the stark252 base field.
  • Loading branch information
PatStiles authored and yshekel committed May 19, 2024
1 parent 34fa26a commit c329559
Show file tree
Hide file tree
Showing 15 changed files with 860 additions and 5 deletions.
13 changes: 10 additions & 3 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ jobs:
if: needs.check-changed-files.outputs.rust == 'true' || needs.check-changed-files.outputs.cpp_cuda == 'true'
# Running tests from the root workspace will run all workspace members' tests by default
# We need to limit the number of threads to avoid running out of memory on weaker machines
# ignored tests are polynomial tests. Since they conflict with NTT tests, they are executed sperately
# ignored tests are polynomial tests. Since they conflict with NTT tests, they are executed separately
run: |
cargo test --workspace --exclude icicle-babybear --release --verbose --features=g2 -- --test-threads=2 --ignored
cargo test --workspace --exclude icicle-babybear --release --verbose --features=g2 -- --test-threads=2
cargo test --workspace --exclude icicle-babybear --exclude icicle-stark252 --release --verbose --features=g2 -- --test-threads=2 --ignored
cargo test --workspace --exclude icicle-babybear --exclude icicle-stark252 --release --verbose --features=g2 -- --test-threads=2
- name: Run baby bear tests
working-directory: ./wrappers/rust/icicle-fields/icicle-babybear
Expand All @@ -72,6 +72,13 @@ jobs:
cargo test --release --verbose -- --ignored
cargo test --release --verbose
- name: Run stark252 tests
working-directory: ./wrappers/rust/icicle-fields/icicle-stark252
if: needs.check-changed-files.outputs.rust == 'true' || needs.check-changed-files.outputs.cpp_cuda == 'true'
run: |
cargo test --release --verbose -- --ignored
cargo test --release --verbose
build-windows:
name: Build on Windows
runs-on: windows-2022
Expand Down
4 changes: 2 additions & 2 deletions icicle/cmake/FieldsCommon.cmake
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
function(check_field)
set(SUPPORTED_FIELDS babybear)
set(SUPPORTED_FIELDS babybear;stark252)

set(IS_FIELD_SUPPORTED FALSE)
set(I 1000)
Expand All @@ -14,4 +14,4 @@ function(check_field)
if (NOT IS_FIELD_SUPPORTED)
message( FATAL_ERROR "The value of FIELD variable: ${FIELD} is not one of the supported fields: ${SUPPORTED_FIELDS}" )
endif ()
endfunction()
endfunction()
47 changes: 47 additions & 0 deletions icicle/include/api/stark252.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// WARNING: This file is auto-generated by a script.
// Any changes made to this file may be overwritten.
// Please modify the code generation script instead.
// Path to the code generation script: scripts/gen_c_api.py

#pragma once
#ifndef STARK252_API_H
#define STARK252_API_H

#include <cuda_runtime.h>
#include "gpu-utils/device_context.cuh"
#include "fields/stark_fields/stark252.cuh"
#include "ntt/ntt.cuh"
#include "vec_ops/vec_ops.cuh"

extern "C" cudaError_t stark252_mul_cuda(
stark252::scalar_t* vec_a, stark252::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config, stark252::scalar_t* result);

extern "C" cudaError_t stark252_add_cuda(
stark252::scalar_t* vec_a, stark252::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config, stark252::scalar_t* result);

extern "C" cudaError_t stark252_sub_cuda(
stark252::scalar_t* vec_a, stark252::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config, stark252::scalar_t* result);

extern "C" cudaError_t stark252_transpose_matrix_cuda(
const stark252::scalar_t* input,
uint32_t row_size,
uint32_t column_size,
stark252::scalar_t* output,
device_context::DeviceContext& ctx,
bool on_device,
bool is_async);

extern "C" void stark252_generate_scalars(stark252::scalar_t* scalars, int size);

extern "C" cudaError_t stark252_scalar_convert_montgomery(
stark252::scalar_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx);

extern "C" cudaError_t stark252_initialize_domain(
stark252::scalar_t* primitive_root, device_context::DeviceContext& ctx, bool fast_twiddles_mode);

extern "C" cudaError_t stark252_ntt_cuda(
const stark252::scalar_t* input, int size, ntt::NTTDir dir, ntt::NTTConfig<stark252::scalar_t>& config, stark252::scalar_t* output);

extern "C" cudaError_t stark252_release_domain(device_context::DeviceContext& ctx);

#endif
3 changes: 3 additions & 0 deletions icicle/include/fields/field_config.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ namespace field_config = grumpkin;
#elif FIELD_ID == BABY_BEAR
#include "fields/stark_fields/babybear.cuh"
namespace field_config = babybear;
#elif FIELD_ID == STARK_252
#include "fields/stark_fields/stark252.cuh"
namespace field_config = stark252;
#endif

#endif
1 change: 1 addition & 0 deletions icicle/include/fields/id.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
#define GRUMPKIN 5

#define BABY_BEAR 1001
#define STARK_252 1002

#endif
631 changes: 631 additions & 0 deletions icicle/include/fields/stark_fields/stark252.cuh

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions scripts/gen_c_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@
FIELDS_CONFIG = {
"babybear": {
"poseidon.h",
},
"stark252": {
"poseidon.h",
"field_ext.h",
"vec_ops_ext.h",
"ntt_ext.h",
}
}

Expand Down
1 change: 1 addition & 0 deletions wrappers/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ members = [
"icicle-curves/icicle-bn254",
"icicle-curves/icicle-grumpkin",
"icicle-fields/icicle-babybear",
"icicle-fields/icicle-stark252",
"icicle-hash",
]
exclude = [
Expand Down
22 changes: 22 additions & 0 deletions wrappers/rust/icicle-fields/icicle-stark252/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"]
24 changes: 24 additions & 0 deletions wrappers/rust/icicle-fields/icicle-stark252/build.rs
Original file line number Diff line number Diff line change
@@ -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");
}
19 changes: 19 additions & 0 deletions wrappers/rust/icicle-fields/icicle-stark252/src/field.rs
Original file line number Diff line number Diff line change
@@ -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);
}
4 changes: 4 additions & 0 deletions wrappers/rust/icicle-fields/icicle-stark252/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub mod field;
pub mod ntt;
pub mod polynomials;
pub mod vec_ops;
60 changes: 60 additions & 0 deletions wrappers/rust/icicle-fields/icicle-stark252/src/ntt/mod.rs
Original file line number Diff line number Diff line change
@@ -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());
}
}
}
}
10 changes: 10 additions & 0 deletions wrappers/rust/icicle-fields/icicle-stark252/src/polynomials/mod.rs
Original file line number Diff line number Diff line change
@@ -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);
}
20 changes: 20 additions & 0 deletions wrappers/rust/icicle-fields/icicle-stark252/src/vec_ops/mod.rs
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit c329559

Please sign in to comment.