-
Notifications
You must be signed in to change notification settings - Fork 140
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Circle starks #924
Merged
Merged
Circle starks #924
Changes from all commits
Commits
Show all changes
86 commits
Select commit
Hold shift + click to select a range
852f856
optimize add
0d68798
save changes. Add, sub and mul checked
5ebc30a
fix tests
ColoCarletti 81439ae
add new inv
ColoCarletti 47cf7da
add mult by powers of two
2acfdd7
Merge branch 'optimize_mersenne31' of github.com:lambdaclass/lambdawo…
cfba8bc
replace inverse
01eba0d
test new inv
ColoCarletti 60fd981
modify old algorithm for inv
ColoCarletti 996e224
fix tests extension
c41b977
Merge branch 'optimize_mersenne31' of github.com:lambdaclass/lambdawo…
28d8b0e
add mul for degree 4 extension
5e1f533
add fp4 isField and isSubField operations and benchmarks
fde7faa
new version for fp4 mul based on the paper
60c8197
add mul of a fp2e by non-residue
25b8869
change inv using mul_fp2_by_non_resiude
1187be8
save work
ecff11e
wip fp2 test
ColoCarletti a6169ea
Merge branch 'optimize_mersenne31' of github.com:lambdaclass/lambdawo…
ColoCarletti ae1446a
add fp2 tests
ColoCarletti fa12fc5
add 2 * a^2 - 1 function
461485b
use karatsuba in fp4 mul version 1
d4e3f40
clean up
ColoCarletti f0437c7
fix Fp as subfield of Fp2. Tests Fp plus Fp4 is now correct
2c5a301
fix inv
ColoCarletti 4a42dbc
fix comments
ColoCarletti 21d09c6
create crate
ColoCarletti f7efd90
Revert "create crate"
ColoCarletti db3ab30
Merge branch 'optimize_mersenne31' into circle-starks
ColoCarletti eddd9be
add circle point implementation
ColoCarletti ba738c7
add group order
ColoCarletti 85d80c1
rm dependencie
ColoCarletti 14a7beb
add cosets
ColoCarletti b56d212
add twiddle
ColoCarletti 58aeb0c
init cfft
ColoCarletti a85eb0f
test cfft
ColoCarletti 6bda70d
test 16 not working
7cbd173
fix n16 test
ColoCarletti 4f60a48
refactor
ColoCarletti 35a9d5a
Merge branch 'main' into circle-starks
ColoCarletti 95e87d0
clippy
ColoCarletti 10636f9
fmt
ColoCarletti c76793f
Merge branch 'main' into circle-starks
diegokingston 876459d
clippy
ColoCarletti dcdd18a
Merge branch 'circle-starks' of github.com:lambdaclass/lambdaworks in…
ColoCarletti 076b683
rm std
ColoCarletti 0d7d89f
add alloc
ColoCarletti 9685a74
fix
ColoCarletti ac842bf
wip
ColoCarletti 52655b1
Merge branch 'main' into circle-starks
ColoCarletti 5f97990
add hand iterpolation for 4 and 8
ColoCarletti dc4124e
wip
ColoCarletti 56dae17
evaluation and interpolation working
2546ca2
add tests and comments
57735cf
Merge branch 'main' into circle-starks
ColoCarletti da5fae7
clippy
ColoCarletti 1166a42
Merge branch 'circle-starks' of github.com:lambdaclass/lambdaworks in…
ColoCarletti 28ab71f
fmt
ColoCarletti e0c666d
remove unused functions
ColoCarletti 3073470
add comment
ColoCarletti 37aae9e
Update math/src/circle/polynomial.rs
nicole-graus 4436e28
change generator and order CirclePoint functions as constants
835a565
impl eq as PartialEq
2ea3171
implement scalar_mul as Mul
c9acb74
Change error name to a more descriptive one and move it to point.rs
93fd515
fix lint
7ae4990
fix lint
8801317
fix some comments
7fe6a7d
Merge branch 'main' into circle-starks
diegokingston 8b2b3d2
add alloc::vec
ColoCarletti ebc5e9d
fix no-std
ColoCarletti f3028e5
cargo fmt
ColoCarletti b645a7b
fix no-std
ColoCarletti c7cfd8f
remove macro
ColoCarletti fc68bea
add comment
ColoCarletti 0a50704
addition between referenced and non-referenced values
a045516
Update math/src/circle/point.rs
nicole-graus c00a223
explain why won't panic
9ff3233
Merge branch 'circle-starks' of github.com:lambdaclass/lambdaworks in…
e0fa390
add errors.rs
ColoCarletti 3ed8ac1
fix vec
a7161f2
Evaluate and interpolate functions have non-mutable inputs
b88794f
fix clippy
b2e9b9d
MulAssign for points and double function takes a reference
26d6078
Revert "MulAssign for points and double function takes a reference"
a6738c7
MulAssign and AddAssign
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,220 @@ | ||
extern crate alloc; | ||
use crate::field::{element::FieldElement, fields::mersenne31::field::Mersenne31Field}; | ||
use alloc::vec::Vec; | ||
|
||
#[cfg(feature = "alloc")] | ||
/// 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. | ||
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 | ||
}); | ||
}); | ||
}); | ||
} | ||
|
||
#[cfg(feature = "alloc")] | ||
/// The inverse fft algorithm used to interpolate 2^n points. | ||
/// Input must be of size 2^n for some n. | ||
pub fn icfft( | ||
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 icfft has n layers. | ||
(0..log_2_size).for_each(|i| { | ||
// In each layer i we split the current input in chunks of size 2^{n - i}. | ||
let chunk_size = 1 << (log_2_size - i); | ||
let half_chunk_size = chunk_size >> 1; | ||
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 = *hi + *low; | ||
*low = (*hi - *low) * twiddles[i as usize][j]; | ||
*hi = temp; | ||
}); | ||
}); | ||
}); | ||
} | ||
|
||
/// This function permutes a slice of field elements to order the result of the cfft in the natural way. | ||
/// We call the natural order to [P(x0, y0), P(x1, y1), P(x2, y2), ...], | ||
/// where (x0, y0) is the first point of the corresponding coset. | ||
/// The cfft doesn't return the evaluations in the natural order. | ||
/// For example, if we apply the cfft to 8 coefficients of a polynomial of degree 7 we'll get the evaluations in this order: | ||
/// [P(x0, y0), P(x2, y2), P(x4, y4), P(x6, y6), P(x7, y7), P(x5, y5), P(x3, y3), P(x1, y1)], | ||
/// where the even indices are found first in ascending order and then the odd indices in descending order. | ||
/// This function permutes the slice [0, 2, 4, 6, 7, 5, 3, 1] into [0, 1, 2, 3, 4, 5, 6, 7]. | ||
/// TODO: This can be optimized by performing in-place value swapping (WIP). | ||
pub fn order_cfft_result_naive( | ||
input: &[FieldElement<Mersenne31Field>], | ||
) -> Vec<FieldElement<Mersenne31Field>> { | ||
let mut result = Vec::new(); | ||
let length = input.len(); | ||
for i in 0..length / 2 { | ||
result.push(input[i]); // We push the left index. | ||
result.push(input[length - i - 1]); // We push the right index. | ||
} | ||
result | ||
} | ||
|
||
/// This function permutes a slice of field elements to order the input of the icfft in a specific way. | ||
/// For example, if we want to interpolate 8 points we should input them in the icfft in this order: | ||
/// [(x0, y0), (x2, y2), (x4, y4), (x6, y6), (x7, y7), (x5, y5), (x3, y3), (x1, y1)], | ||
/// where the even indices are found first in ascending order and then the odd indices in descending order. | ||
/// This function permutes the slice [0, 1, 2, 3, 4, 5, 6, 7] into [0, 2, 4, 6, 7, 5, 3, 1]. | ||
/// TODO: This can be optimized by performing in-place value swapping (WIP). | ||
pub fn order_icfft_input_naive( | ||
input: &mut [FieldElement<Mersenne31Field>], | ||
) -> Vec<FieldElement<Mersenne31Field>> { | ||
let mut result = Vec::new(); | ||
|
||
// We push the even indices. | ||
(0..input.len()).step_by(2).for_each(|i| { | ||
result.push(input[i]); | ||
}); | ||
|
||
// We push the odd indices. | ||
(1..input.len()).step_by(2).rev().for_each(|i| { | ||
result.push(input[i]); | ||
}); | ||
result | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
type FE = FieldElement<Mersenne31Field>; | ||
|
||
#[test] | ||
fn ordering_cfft_result_works_for_4_points() { | ||
let expected_slice = [FE::from(0), FE::from(1), FE::from(2), FE::from(3)]; | ||
|
||
let slice = [FE::from(0), FE::from(2), FE::from(3), FE::from(1)]; | ||
|
||
let res = order_cfft_result_naive(&slice); | ||
|
||
assert_eq!(res, expected_slice) | ||
} | ||
|
||
#[test] | ||
fn ordering_cfft_result_works_for_16_points() { | ||
let expected_slice = [ | ||
FE::from(0), | ||
FE::from(1), | ||
FE::from(2), | ||
FE::from(3), | ||
FE::from(4), | ||
FE::from(5), | ||
FE::from(6), | ||
FE::from(7), | ||
FE::from(8), | ||
FE::from(9), | ||
FE::from(10), | ||
FE::from(11), | ||
FE::from(12), | ||
FE::from(13), | ||
FE::from(14), | ||
FE::from(15), | ||
]; | ||
|
||
let slice = [ | ||
FE::from(0), | ||
FE::from(2), | ||
FE::from(4), | ||
FE::from(6), | ||
FE::from(8), | ||
FE::from(10), | ||
FE::from(12), | ||
FE::from(14), | ||
FE::from(15), | ||
FE::from(13), | ||
FE::from(11), | ||
FE::from(9), | ||
FE::from(7), | ||
FE::from(5), | ||
FE::from(3), | ||
FE::from(1), | ||
]; | ||
|
||
let res = order_cfft_result_naive(&slice); | ||
|
||
assert_eq!(res, expected_slice) | ||
} | ||
|
||
#[test] | ||
fn from_natural_to_icfft_input_order_works() { | ||
let mut slice = [ | ||
FE::from(0), | ||
FE::from(1), | ||
FE::from(2), | ||
FE::from(3), | ||
FE::from(4), | ||
FE::from(5), | ||
FE::from(6), | ||
FE::from(7), | ||
FE::from(8), | ||
FE::from(9), | ||
FE::from(10), | ||
FE::from(11), | ||
FE::from(12), | ||
FE::from(13), | ||
FE::from(14), | ||
FE::from(15), | ||
]; | ||
|
||
let expected_slice = [ | ||
FE::from(0), | ||
FE::from(2), | ||
FE::from(4), | ||
FE::from(6), | ||
FE::from(8), | ||
FE::from(10), | ||
FE::from(12), | ||
FE::from(14), | ||
FE::from(15), | ||
FE::from(13), | ||
FE::from(11), | ||
FE::from(9), | ||
FE::from(7), | ||
FE::from(5), | ||
FE::from(3), | ||
FE::from(1), | ||
]; | ||
|
||
let res = order_icfft_input_naive(&mut slice); | ||
|
||
assert_eq!(res, expected_slice) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
extern crate alloc; | ||
use crate::circle::point::CirclePoint; | ||
use crate::field::fields::mersenne31::field::Mersenne31Field; | ||
use alloc::vec::Vec; | ||
|
||
/// Given g_n, a generator of the subgroup of size n of the circle, i.e. <g_n>, | ||
/// and given a shift, that is a another point of the circle, | ||
/// we define the coset shift + <g_n> which is the set of all the points in | ||
/// <g_n> plus the shift. | ||
/// For example, if <g_4> = {p1, p2, p3, p4}, then g_8 + <g_4> = {g_8 + p1, g_8 + p2, g_8 + p3, g_8 + p4}. | ||
|
||
#[derive(Debug, Clone)] | ||
pub struct Coset { | ||
// Coset: shift + <g_n> where n = 2^{log_2_size}. | ||
// Example: g_16 + <g_8>, n = 8, log_2_size = 3, shift = g_16. | ||
pub log_2_size: u32, //TODO: Change log_2_size to u8 because log_2_size < 31. | ||
pub shift: CirclePoint<Mersenne31Field>, | ||
} | ||
|
||
impl Coset { | ||
pub fn new(log_2_size: u32, shift: CirclePoint<Mersenne31Field>) -> Self { | ||
Coset { log_2_size, shift } | ||
} | ||
|
||
/// Returns the coset g_2n + <g_n> | ||
pub fn new_standard(log_2_size: u32) -> Self { | ||
// shift is a generator of the subgroup of order 2n = 2^{log_2_size + 1}. | ||
let shift = CirclePoint::get_generator_of_subgroup(log_2_size + 1); | ||
Coset { log_2_size, shift } | ||
} | ||
|
||
/// Returns g_n, the generator of the subgroup of order n = 2^log_2_size. | ||
pub fn get_generator(&self) -> CirclePoint<Mersenne31Field> { | ||
CirclePoint::GENERATOR.repeated_double(31 - self.log_2_size) | ||
} | ||
|
||
/// Given a standard coset g_2n + <g_n>, returns the subcoset with half size g_2n + <g_{n/2}> | ||
pub fn half_coset(coset: Self) -> Self { | ||
Coset { | ||
log_2_size: coset.log_2_size - 1, | ||
shift: coset.shift, | ||
} | ||
} | ||
|
||
/// Given a coset shift + G returns the coset -shift + G. | ||
/// Note that (g_2n + <g_{n/2}>) U (-g_2n + <g_{n/2}>) = g_2n + <g_n>. | ||
pub fn conjugate(coset: Self) -> Self { | ||
Coset { | ||
log_2_size: coset.log_2_size, | ||
shift: coset.shift.conjugate(), | ||
} | ||
} | ||
|
||
/// Returns the vector of shift + g for every g in <g_n>. | ||
/// where g = i * g_n for i = 0, ..., n-1. | ||
#[cfg(feature = "alloc")] | ||
pub fn get_coset_points(coset: &Self) -> Vec<CirclePoint<Mersenne31Field>> { | ||
// g_n the generator of the subgroup of order n. | ||
let generator_n = CirclePoint::get_generator_of_subgroup(coset.log_2_size); | ||
let size: u8 = 1 << coset.log_2_size; | ||
core::iter::successors(Some(coset.shift.clone()), move |prev| { | ||
Some(prev + &generator_n) | ||
}) | ||
.take(size.into()) | ||
.collect() | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[test] | ||
fn coset_points_vector_has_right_size() { | ||
let coset = Coset::new_standard(3); | ||
let points = Coset::get_coset_points(&coset); | ||
assert_eq!(1 << coset.log_2_size, points.len()) | ||
} | ||
|
||
#[test] | ||
fn antipode_of_coset_point_is_in_coset() { | ||
let coset = Coset::new_standard(3); | ||
let points = Coset::get_coset_points(&coset); | ||
let point = points[2].clone(); | ||
let anitpode_point = points[6].clone(); | ||
assert_eq!(anitpode_point, point.antipode()) | ||
} | ||
|
||
#[test] | ||
fn coset_generator_has_right_order() { | ||
let coset = Coset::new(2, CirclePoint::GENERATOR * 3); | ||
let generator_n = coset.get_generator(); | ||
assert_eq!(generator_n.repeated_double(2), CirclePoint::zero()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#[derive(Debug)] | ||
pub enum CircleError { | ||
PointDoesntSatisfyCircleEquation, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
pub mod cfft; | ||
pub mod cosets; | ||
pub mod errors; | ||
pub mod point; | ||
pub mod polynomial; | ||
pub mod twiddles; |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we can use interleave
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would not solve the memory usage problem. There is a way to do it in-place recursively, but we thought it would be better to implement that when we need to optimize.