pub fn cfft(
    input: &mut [FieldElement<Mersenne31Field>],
    twiddles: Vec<Vec<FieldElement<Mersenne31Field>>>,
) {
    // If the input size is 2^n, then log_2_size is n.
    let log_2_size = input.len().trailing_zeros();

    // The cfft has n layers.
    (0..log_2_size).for_each(|i| {
        // In each layer i we split the current input in chunks of size 2^{i+1}.
        let chunk_size = 1 << (i + 1);
        let half_chunk_size = 1 << i;
        input.chunks_mut(chunk_size).for_each(|chunk| {
            // We split each chunk in half, calling the first half hi_part and the second hal low_part.
            let (hi_part, low_part) = chunk.split_at_mut(half_chunk_size);

            // We apply the corresponding butterfly for every element j of the high and low part.
            hi_part
                .iter_mut()
                .zip(low_part)
                .enumerate()
                .for_each(|(j, (hi, low))| {
                    let temp = *low * twiddles[i as usize][j];
                    *low = *hi - temp;
                    *hi += temp
                });
        });
    });
}
fft in place algorithm used to evaluate a polynomial of degree 2^n - 1 in 2^n points.
Input must be of size 2^n for some n.
crates/math/src/circle/cfft.rs