Skip to content

Commit

Permalink
Merge branch 'main' into affine-serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
MauroToscano authored Dec 18, 2023
2 parents cca8e8b + 6063197 commit 1101187
Show file tree
Hide file tree
Showing 41 changed files with 1,238 additions and 413 deletions.
11 changes: 11 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@ lambdaworks-math = { path = "./math", version = "0.3.0" }
stark-platinum-prover = { path = "./provers/stark", version = "0.3.0" }
cairo-platinum-prover = { path = "./provers/cairo", version = "0.3.0" }

[patch.crates-io]
winter-air = { git = "https://github.com/lambdaclass/winterfell-for-lambdaworks.git", branch = "derive-clone-v6.4"}
winter-prover = { git = "https://github.com/lambdaclass/winterfell-for-lambdaworks.git", branch = "derive-clone-v6.4"}
winter-math = { git = "https://github.com/lambdaclass/winterfell-for-lambdaworks.git", branch = "derive-clone-v6.4"}
winter-utils = { git = "https://github.com/lambdaclass/winterfell-for-lambdaworks.git", branch = "derive-clone-v6.4"}
winter-crypto = { git = "https://github.com/lambdaclass/winterfell-for-lambdaworks.git", branch = "derive-clone-v6.4"}
miden-air = { git = "https://github.com/lambdaclass/miden-vm" }
miden-core = { git = "https://github.com/lambdaclass/miden-vm" }
miden-assembly = { git = "https://github.com/lambdaclass/miden-vm" }
miden-processor = { git = "https://github.com/lambdaclass/miden-vm" }

[profile.bench]
lto = true
codegen-units = 1
Expand Down
4 changes: 4 additions & 0 deletions math/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ thiserror = { version = "1.0", optional = true }
serde = { version = "1.0", features = ["derive"], optional = true }
serde_json = { version = "1.0", optional = true }
proptest = { version = "1.1.0", optional = true }
winter-math = { package = "winter-math", version = "0.6.4", default-features = false, optional = true }
miden-core = { package = "miden-core" , version = "0.7", default-features = false, optional = true }

# rayon
rayon = { version = "1.7", optional = true }
Expand Down Expand Up @@ -41,6 +43,7 @@ std = ["dep:thiserror"]
lambdaworks-serde-binary = ["dep:serde", "std"]
lambdaworks-serde-string = ["dep:serde", "dep:serde_json", "std"]
proptest = ["dep:proptest"]
winter_compatibility = ["winter-math", "miden-core"]

# gpu
metal = [
Expand Down Expand Up @@ -88,3 +91,4 @@ harness = false
name = "criterion_metal"
harness = false
required-features = ["metal"]

8 changes: 3 additions & 5 deletions math/benches/utils/fft_functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ use lambdaworks_math::fft::cpu::{
fft::{in_place_nr_2radix_fft, in_place_rn_2radix_fft},
roots_of_unity::get_twiddles,
};
use lambdaworks_math::{
fft::polynomial::FFTPoly, field::traits::RootsConfig, polynomial::Polynomial,
};
use lambdaworks_math::{field::traits::RootsConfig, polynomial::Polynomial};

use super::stark252_utils::{F, FE};

Expand All @@ -29,9 +27,9 @@ pub fn bitrev_permute(input: &mut [FE]) {
}

pub fn poly_evaluate_fft(poly: &Polynomial<FE>) -> Vec<FE> {
poly.evaluate_fft(black_box(1), black_box(None)).unwrap()
Polynomial::evaluate_fft::<F>(poly, black_box(1), black_box(None)).unwrap()
}

pub fn poly_interpolate_fft(evals: &[FE]) {
Polynomial::interpolate_fft(evals).unwrap();
Polynomial::interpolate_fft::<F>(evals).unwrap();
}
5 changes: 2 additions & 3 deletions math/benches/utils/metal_functions.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use lambdaworks_gpu::metal::abstractions::state::MetalState;
use lambdaworks_math::fft::gpu::metal::ops::*;
use lambdaworks_math::fft::polynomial::FFTPoly;
use lambdaworks_math::{field::traits::RootsConfig, polynomial::Polynomial};

// WARN: These should always be fields supported by Metal, else the last two benches will use CPU FFT.
Expand All @@ -22,8 +21,8 @@ pub fn bitrev_permute(input: &[FE]) {
}

pub fn poly_evaluate_fft(poly: &Polynomial<FE>) {
poly.evaluate_fft(1, None).unwrap();
Polynomial::evaluate_fft::<F>(poly, 1, None).unwrap();
}
pub fn poly_interpolate_fft(evals: &[FE]) {
Polynomial::interpolate_fft(evals).unwrap();
Polynomial::interpolate_fft::<F>(evals).unwrap();
}
16 changes: 12 additions & 4 deletions math/src/fft/cpu/fft.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::field::{element::FieldElement, traits::IsFFTField};
use crate::field::{
element::FieldElement,
traits::{IsFFTField, IsField, IsSubFieldOf},
};

/// In-Place Radix-2 NR DIT FFT algorithm over a slice of two-adic field elements.
/// It's required that the twiddle factors are in bit-reverse order. Else this function will not
Expand All @@ -12,9 +15,12 @@ use crate::field::{element::FieldElement, traits::IsFFTField};
/// - NR: natural to reverse order, meaning that the input is naturally ordered and the output will
/// be bit-reversed ordered.
/// - DIT: decimation in time
pub fn in_place_nr_2radix_fft<F>(input: &mut [FieldElement<F>], twiddles: &[FieldElement<F>])
///
/// It supports values in a field E and domain in a subfield F.
pub fn in_place_nr_2radix_fft<F, E>(input: &mut [FieldElement<E>], twiddles: &[FieldElement<F>])
where
F: IsFFTField,
F: IsFFTField + IsSubFieldOf<E>,
E: IsField,
{
// divide input in groups, starting with 1, duplicating the number of groups in each stage.
let mut group_count = 1;
Expand Down Expand Up @@ -60,6 +66,8 @@ where
/// - RN: reverse to natural order, meaning that the input is bit-reversed ordered and the output will
/// be naturally ordered.
/// - DIT: decimation in time
///
/// It supports values in a field E and domain in a subfield F.
#[allow(dead_code)]
pub fn in_place_rn_2radix_fft<F>(input: &mut [FieldElement<F>], twiddles: &[FieldElement<F>])
where
Expand Down Expand Up @@ -135,7 +143,7 @@ mod tests {
let twiddles = get_twiddles(order.into(), RootsConfig::BitReverse).unwrap();

let mut result = coeffs;
in_place_nr_2radix_fft(&mut result, &twiddles);
in_place_nr_2radix_fft::<F, F>(&mut result, &twiddles);
in_place_bit_reverse_permute(&mut result);

prop_assert_eq!(expected, result);
Expand Down
15 changes: 9 additions & 6 deletions math/src/fft/cpu/ops.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
use crate::{
fft::errors::FFTError,
field::{element::FieldElement, traits::IsFFTField},
field::{
element::FieldElement,
traits::{IsFFTField, IsField, IsSubFieldOf},
},
};

use super::{bit_reversing::in_place_bit_reverse_permute, fft::in_place_nr_2radix_fft};

/// Executes Fast Fourier Transform over elements of a two-adic finite field `F`. Usually used for
/// fast polynomial evaluation.
pub fn fft<F: IsFFTField>(
input: &[FieldElement<F>],
/// Executes Fast Fourier Transform over elements of a two-adic finite field `E` and domain in a
/// subfield `F`. Usually used for fast polynomial evaluation.
pub fn fft<F: IsFFTField + IsSubFieldOf<E>, E: IsField>(
input: &[FieldElement<E>],
twiddles: &[FieldElement<F>],
) -> Result<Vec<FieldElement<F>>, FFTError> {
) -> Result<Vec<FieldElement<E>>, FFTError> {
if !input.len().is_power_of_two() {
return Err(FFTError::InputError(input.len()));
}
Expand Down
2 changes: 1 addition & 1 deletion math/src/fft/cpu/roots_of_unity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ pub fn get_powers_of_primitive_root_coset<F: IsFFTField>(
offset: &FieldElement<F>,
) -> Result<Vec<FieldElement<F>>, FFTError> {
let root = F::get_primitive_root_of_unity(n)?;
let results = (0..count).map(|i| root.pow(i) * offset);
let results = (0..count).map(|i| offset * root.pow(i));

Ok(results.collect())
}
Expand Down
18 changes: 12 additions & 6 deletions math/src/fft/gpu/metal/ops.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::field::{
element::FieldElement,
traits::{IsFFTField, RootsConfig},
traits::{IsFFTField, IsField, IsSubFieldOf, RootsConfig},
};
use lambdaworks_gpu::metal::abstractions::{errors::MetalError, state::*};

Expand All @@ -15,11 +15,17 @@ use core::mem;
/// in this order too. Natural order means that input[i] corresponds to the i-th coefficient,
/// as opposed to bit-reverse order in which input[bit_rev(i)] corresponds to the i-th
/// coefficient.
pub fn fft<F: IsFFTField>(
input: &[FieldElement<F>],
///
/// It supports values in a field E and domain in a subfield F.
pub fn fft<F, E>(
input: &[FieldElement<E>],
twiddles: &[FieldElement<F>],
state: &MetalState,
) -> Result<Vec<FieldElement<F>>, MetalError> {
) -> Result<Vec<FieldElement<E>>, MetalError>
where
F: IsFFTField + IsSubFieldOf<E>,
E: IsField,
{
// TODO: make a twiddle factor abstraction for handling invalid twiddles
if !input.len().is_power_of_two() {
return Err(MetalError::InputError(input.len()));
Expand Down Expand Up @@ -173,7 +179,7 @@ mod tests {
fn test_metal_fft_matches_sequential(input in field_vec(6)) {
let metal_state = MetalState::new(None).unwrap();
let order = input.len().trailing_zeros();
let twiddles = get_twiddles(order.into(), RootsConfig::BitReverse).unwrap();
let twiddles = get_twiddles::<F>(order.into(), RootsConfig::BitReverse).unwrap();

let metal_result = super::fft(&input, &twiddles, &metal_state).unwrap();
let sequential_result = crate::fft::cpu::ops::fft(&input, &twiddles).unwrap();
Expand All @@ -190,7 +196,7 @@ mod tests {

let metal_state = MetalState::new(None).unwrap();
let order = input.len().trailing_zeros();
let twiddles = get_twiddles(order.into(), RootsConfig::BitReverse).unwrap();
let twiddles = get_twiddles::<F>(order.into(), RootsConfig::BitReverse).unwrap();

let metal_result = super::fft(&input, &twiddles, &metal_state).unwrap();
let sequential_result = crate::fft::cpu::ops::fft(&input, &twiddles).unwrap();
Expand Down
22 changes: 13 additions & 9 deletions math/src/fft/gpu/metal/polynomial.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,42 @@
use crate::{
field::{
element::FieldElement,
traits::{IsFFTField, RootsConfig},
traits::{IsFFTField, IsField, IsSubFieldOf, RootsConfig},
},
polynomial::Polynomial,
};
use lambdaworks_gpu::metal::abstractions::{errors::MetalError, state::MetalState};

use super::ops::*;

pub fn evaluate_fft_metal<F>(coeffs: &[FieldElement<F>]) -> Result<Vec<FieldElement<F>>, MetalError>
pub fn evaluate_fft_metal<F, E>(
coeffs: &[FieldElement<E>],
) -> Result<Vec<FieldElement<E>>, MetalError>
where
F: IsFFTField,
F: IsFFTField + IsSubFieldOf<E>,
E: IsField,
{
let state = MetalState::new(None)?;

let order = coeffs.len().trailing_zeros();
let twiddles = gen_twiddles(order.into(), RootsConfig::BitReverse, &state)?;
let twiddles = gen_twiddles::<F>(order.into(), RootsConfig::BitReverse, &state)?;

fft(coeffs, &twiddles, &state)
}

/// Returns a new polynomial that interpolates `fft_evals`, which are evaluations using twiddle
/// factors. This is considered to be the inverse operation of [evaluate_fft_metal()].
pub fn interpolate_fft_metal<F>(
fft_evals: &[FieldElement<F>],
) -> Result<Polynomial<FieldElement<F>>, MetalError>
pub fn interpolate_fft_metal<F, E>(
fft_evals: &[FieldElement<E>],
) -> Result<Polynomial<FieldElement<E>>, MetalError>
where
F: IsFFTField,
F: IsFFTField + IsSubFieldOf<E>,
E: IsField,
{
let metal_state = MetalState::new(None)?;

let order = fft_evals.len().trailing_zeros();
let twiddles = gen_twiddles(order.into(), RootsConfig::BitReverseInversed, &metal_state)?;
let twiddles = gen_twiddles::<F>(order.into(), RootsConfig::BitReverseInversed, &metal_state)?;

let coeffs = fft(fft_evals, &twiddles, &metal_state)?;

Expand Down
Loading

0 comments on commit 1101187

Please sign in to comment.