@@ -97,20 +97,24 @@ pub fn _ntt<const Q: u64, const D: u64>(coeffs: Vec<Zq<Q>>, psi: Zq<Q>, zeta_exp
9797}
9898
9999
100- // TODO: finish bit reverse
101- // /// Reverse order of the result.
102- // /// Since the result of our NTT would be (w^1, w^5, w^3, w^7) for d=4,
103- // /// but we expect it to be (w^1, w^3, w^5, w^7).
104- // fn _bit_reverse_permutation<T>(v: &mut [T]) {
105- // let n = v.len();
106- // let log_n = n.trailing_zeros();
107- // for i in 0..n {
108- // let j = i.reverse_bits() >> (usize::BITS - log_n);
109- // if i < j {
110- // v.swap(i, j);
111- // }
112- // }
113- // }
100+ /// Reverse order of the result.
101+ /// Since the result of our NTT would be (w^1, w^5, w^3, w^7) for d=4,
102+ /// but we expect it to be (w^1, w^3, w^5, w^7).
103+ /// Intuition:
104+ /// So it's actually dividing elements k s.t. \psi^{2k+1} is a root of x^d+1
105+ /// every layer we put w^{n/2} (even) to the left and -w^{n/2} to the right.
106+ /// So we just map the result from NTT back to (w^1, w^3, w^5, w^7) with bit-reverse permutation
107+
108+ fn _bit_reverse_permutation < T > ( v : & mut [ T ] ) {
109+ let n = v. len ( ) ;
110+ let log_n = n. trailing_zeros ( ) ;
111+ for i in 0 ..n {
112+ let j = i. reverse_bits ( ) >> ( usize:: BITS - log_n) ;
113+ if i < j {
114+ v. swap ( i, j) ;
115+ }
116+ }
117+ }
114118
115119
116120/// NTT: split polynomials X^d+1 into irreducibles. For negacyclic (X^d+1), to fully split the
@@ -123,11 +127,19 @@ pub fn ntt<const Q: u64, const D: u64>(coeffs: Vec<Zq<Q>>, psi: Zq<Q>) -> Vec<Zq
123127 assert ! ( ( Q -1 ) . is_multiple_of( 2 * D as u64 ) ) ;
124128
125129 let mut result = _ntt :: < Q , D > ( coeffs, psi, D ) ;
126- // _bit_reverse_permutation(&mut result);
130+ _bit_reverse_permutation ( & mut result) ;
127131 result
128132}
129133
130- pub fn intt < const Q : u64 > ( evals : Vec < Zq < Q > > ) -> Vec < Zq < Q > > {
134+
135+ pub fn intt < const Q : u64 , const D : u64 > ( evals : Vec < Zq < Q > > , psi : Zq < Q > ) -> Vec < Zq < Q > > {
136+ assert ! ( D . is_power_of_two( ) , "d should be power of two to split completely: d={D}" ) ;
137+ assert ! ( ( Q -1 ) . is_multiple_of( 2 * D as u64 ) ) ;
138+ todo ! ( )
139+ }
140+
141+
142+ pub fn _intt < const Q : u64 > ( evals : Vec < Zq < Q > > ) -> Vec < Zq < Q > > {
131143 todo ! ( )
132144}
133145
@@ -177,9 +189,10 @@ mod tests {
177189
178190 #[ test]
179191 fn test_intt_backward ( ) {
192+ let psi = setup ( ) ;
180193 let evals = vec ! [ F :: new( 15 ) , F :: new( 0 ) , F :: new( 0 ) , F :: new( 15 ) ] ;
181194 let expected_coeffs = vec ! [ F :: new( 16 ) , F :: new( 3 ) , F :: new( 0 ) , F :: new( 14 ) ] ;
182- assert_eq ! ( intt:: <Q >( evals) , expected_coeffs) ;
195+ assert_eq ! ( intt:: <Q , D >( evals, psi ) , expected_coeffs) ;
183196 }
184197
185198 #[ test]
0 commit comments