@@ -27,7 +27,9 @@ impl<E: IsField> Polynomial<FieldElement<E>> {
2727 ) -> Result < Vec < FieldElement < E > > , FFTError > {
2828 let domain_size = domain_size. unwrap_or ( 0 ) ;
2929 let len = core:: cmp:: max ( poly. coeff_len ( ) , domain_size) . next_power_of_two ( ) * blowup_factor;
30-
30+ if len. trailing_zeros ( ) as u64 > F :: TWO_ADICITY {
31+ return Err ( FFTError :: DomainSizeError ( len. trailing_zeros ( ) as usize ) ) ;
32+ }
3133 if poly. coefficients ( ) . is_empty ( ) {
3234 return Ok ( vec ! [ FieldElement :: zero( ) ; len] ) ;
3335 }
@@ -97,6 +99,22 @@ impl<E: IsField> Polynomial<FieldElement<E>> {
9799 let scaled = Polynomial :: interpolate_fft :: < F > ( fft_evals) ?;
98100 Ok ( scaled. scale ( & offset. inv ( ) . unwrap ( ) ) )
99101 }
102+
103+ /// Multiplies two polynomials using FFT.
104+ /// It's faster than naive multiplication when the degree of the polynomials is large enough (>=2**6).
105+ /// This works best with polynomials whose highest degree is equal to a power of 2 - 1.
106+ /// Will return an error if the degree of the resulting polynomial is greater than 2**63.
107+ pub fn fast_fft_multiplication < F : IsFFTField + IsSubFieldOf < E > > (
108+ & self ,
109+ other : & Self ,
110+ ) -> Result < Self , FFTError > {
111+ let domain_size = self . degree ( ) + other. degree ( ) + 1 ;
112+ let p = Polynomial :: evaluate_fft :: < F > ( self , 1 , Some ( domain_size) ) ?;
113+ let q = Polynomial :: evaluate_fft :: < F > ( other, 1 , Some ( domain_size) ) ?;
114+ let r = p. into_iter ( ) . zip ( q) . map ( |( a, b) | a * b) . collect :: < Vec < _ > > ( ) ;
115+
116+ Polynomial :: interpolate_fft :: < F > ( & r)
117+ }
100118}
101119
102120pub fn compose_fft < F , E > (
@@ -313,6 +331,11 @@ mod tests {
313331
314332 prop_assert_eq!( poly, new_poly) ;
315333 }
334+
335+ #[ test]
336+ fn test_fft_multiplication_works( poly in poly( 7 ) , other in poly( 7 ) ) {
337+ prop_assert_eq!( poly. fast_fft_multiplication:: <F >( & other) . unwrap( ) , poly * other) ;
338+ }
316339 }
317340
318341 #[ test]
@@ -408,6 +431,11 @@ mod tests {
408431 let ( poly, new_poly) = gen_fft_interpolate_and_evaluate( poly) ;
409432 prop_assert_eq!( poly, new_poly) ;
410433 }
434+
435+ #[ test]
436+ fn test_fft_multiplication_works( poly in poly( 7 ) , other in poly( 7 ) ) {
437+ prop_assert_eq!( poly. fast_fft_multiplication:: <F >( & other) . unwrap( ) , poly * other) ;
438+ }
411439 }
412440 }
413441
0 commit comments