#![deny(unsafe_code)]
#![deny(missing_docs)]
#![deny(clippy::unwrap_used)]
#![deny(clippy::panic)]
#![allow(clippy::indexing_slicing)]
pub mod arithmetic;
pub mod montgomery;
pub mod ntt_processor;
pub use montgomery::MontgomeryReducer;
pub use ntt_processor::NttProcessor;
#[cfg(test)]
#[allow(clippy::panic_in_result_fn)] mod tests {
use super::*;
#[test]
fn test_ntt_processor_creation_succeeds() -> Result<(), Box<dyn std::error::Error>> {
let processor = NttProcessor::new(256, 3329)?;
assert_eq!(processor.n, 256);
assert_eq!(processor.modulus, 3329);
Ok(())
}
#[test]
fn test_ntt_roundtrip() -> Result<(), Box<dyn std::error::Error>> {
let processor = NttProcessor::new(256, 3329)?;
let coeffs = (0..256).map(|i| i % 100).collect::<Vec<_>>();
let ntt_result = processor.forward(&coeffs)?;
let recovered = processor.inverse(&ntt_result)?;
for i in 0..256 {
assert!((recovered[i] - coeffs[i]).abs() < 10);
}
Ok(())
}
#[test]
fn test_polynomial_multiplication_succeeds() -> Result<(), Box<dyn std::error::Error>> {
let processor = NttProcessor::new(256, 3329)?;
let _a = [1, 1]; let mut a_padded = vec![0; 256];
if let Some(pos) = a_padded.get_mut(0) {
*pos = 1;
}
if let Some(pos) = a_padded.get_mut(1) {
*pos = 1;
}
let mut b_padded = vec![0; 256];
if let Some(pos) = b_padded.get_mut(0) {
*pos = 1;
}
if let Some(pos) = b_padded.get_mut(1) {
*pos = 1;
}
let result = processor.multiply(&a_padded, &b_padded)?;
assert_eq!(result[0], 1); assert_eq!(result[1], 2); assert_eq!(result[2], 1); Ok(())
}
#[test]
fn test_ntt_processor_invalid_size_fails() {
let result = NttProcessor::new(255, 3329);
assert!(result.is_err());
}
#[test]
fn test_ntt_processor_invalid_modulus_fails() {
let result = NttProcessor::new(256, 12345);
assert!(result.is_err());
}
#[test]
fn test_ntt_processor_different_parameters_succeeds() -> Result<(), Box<dyn std::error::Error>>
{
let processor = NttProcessor::new(512, 12289)?;
assert_eq!(processor.n, 512);
assert_eq!(processor.modulus, 12289);
Ok(())
}
#[test]
fn test_polynomial_multiplication_zero_returns_zero_polynomial_succeeds()
-> Result<(), Box<dyn std::error::Error>> {
let processor = NttProcessor::new(256, 3329)?;
let zero_poly = vec![0; 256];
let test_poly: Vec<_> = (0..256).collect();
let result = processor.multiply(&zero_poly, &test_poly)?;
assert!(result.iter().all(|&x| x == 0));
Ok(())
}
#[test]
fn test_polynomial_multiplication_identity_returns_original_succeeds()
-> Result<(), Box<dyn std::error::Error>> {
let processor = NttProcessor::new(256, 3329)?;
let mut identity = vec![0; 256];
if let Some(pos) = identity.get_mut(0) {
*pos = 1;
}
let test_poly = (0..256).map(|i| i % 10).collect::<Vec<_>>();
let result = processor.multiply(&identity, &test_poly)?;
for (i, &test_val) in test_poly.iter().enumerate() {
if let Some(&result_val) = result.get(i) {
assert!((result_val - test_val).abs() < 5); }
}
Ok(())
}
}