Skip to content

Commit 23d175e

Browse files
committed
fix: Avoid potential panic in (i)NTT
To improve the performance of NTT, some internal data is cached. The key for the cache is the log₂ of the input's length. Previously, the empty input and an input of length 1 mapped to the same cache key. In case NTT had 1. first been called on an empty input, 2. then called on input of length 1, the cache would be incorrectly populated, leading to a panic.
1 parent 27a6541 commit 23d175e

1 file changed

Lines changed: 13 additions & 1 deletion

File tree

twenty-first/src/math/ntt.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,10 @@ where
153153
[const { OnceLock::new() }; NUM_DOMAINS];
154154

155155
let slice_len = x.len();
156-
let log2_slice_len = slice_len.checked_ilog2().unwrap_or(0);
156+
let Some(log2_slice_len) = slice_len.checked_ilog2() else {
157+
// if the slice is empty, there's nothing to do
158+
return;
159+
};
157160
let swap_indices =
158161
ALL_SWAP_INDICES[log2_slice_len as usize].get_or_init(|| swap_indices(slice_len));
159162
debug_assert_eq!(swap_indices.len(), slice_len);
@@ -470,6 +473,15 @@ mod tests {
470473
assert_eq!(vec![bfe], test_vector);
471474
}
472475

476+
// Make sure that caches are correctly populated in edge cases.
477+
#[test]
478+
fn ntt_on_input_of_length_0_then_1_then_0() {
479+
let mut empty = Vec::<BFieldElement>::new();
480+
ntt(&mut empty);
481+
ntt(&mut [BFieldElement::new(0)]);
482+
ntt(&mut empty);
483+
}
484+
473485
#[proptest(cases = 10)]
474486
fn ntt_then_intt_is_identity_operation(
475487
#[strategy((0_usize..18).prop_map(|l| 1 << l))] _vector_length: usize,

0 commit comments

Comments
 (0)