Skip to content

Commit b5d4ceb

Browse files
committed
fix ntt with bit-reverse
1 parent f90f8c9 commit b5d4ceb

1 file changed

Lines changed: 30 additions & 17 deletions

File tree

src/ntt.rs

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)