From b9aa6e5f50cfd6e9321b4425cc56d9291bb05baf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tancr=C3=A8de=20Lepoint?= Date: Sun, 11 Jan 2026 19:40:20 -0500 Subject: [PATCH] fix: Tighten lint expectations and example helpers --- crates/fhe-math/benches/ntt.rs | 5 +---- crates/fhe-math/benches/rns.rs | 5 +---- crates/fhe-math/benches/rq.rs | 9 ++++---- crates/fhe-math/benches/zq.rs | 9 ++++---- crates/fhe-math/src/ntt/native.rs | 7 ++++-- crates/fhe-math/src/proto/mod.rs | 2 -- crates/fhe-math/src/proto/rq.rs | 7 +++--- crates/fhe-math/src/rns/mod.rs | 12 +++++++--- crates/fhe-math/src/rns/scaler.rs | 7 ++++-- crates/fhe-math/src/rq/convert.rs | 2 +- crates/fhe-math/src/rq/mod.rs | 7 ++++-- crates/fhe-math/src/rq/ops.rs | 2 +- crates/fhe-math/src/zq/mod.rs | 1 - crates/fhe-util/src/lib.rs | 22 ++++++++++++++----- crates/fhe/benches/bfv.rs | 9 +++++--- crates/fhe/benches/bfv_optimized_ops.rs | 5 ++--- crates/fhe/benches/bfv_rgsw.rs | 5 ++--- crates/fhe/examples/bfv_basic.rs | 9 +++++--- crates/fhe/examples/bfv_ops.rs | 9 +++++--- crates/fhe/examples/mulpir.rs | 9 +++++--- crates/fhe/examples/pir.rs | 8 ++++--- crates/fhe/examples/rgsw.rs | 9 +++++--- crates/fhe/examples/sealpir.rs | 9 +++++--- crates/fhe/examples/util.rs | 22 +++++++++---------- crates/fhe/examples/voting.rs | 10 +++++---- crates/fhe/src/bfv/ciphertext.rs | 4 ++-- crates/fhe/src/bfv/context/chain.rs | 2 +- crates/fhe/src/bfv/keys/evaluation_key.rs | 4 ---- .../fhe/src/bfv/keys/relinearization_key.rs | 1 - crates/fhe/src/bfv/mod.rs | 7 ++++-- crates/fhe/src/bfv/ops/mul.rs | 1 - crates/fhe/src/bfv/parameters.rs | 9 +++++--- crates/fhe/src/errors.rs | 11 ++++++---- crates/fhe/src/mbfv/mod.rs | 7 ++++-- crates/fhe/src/proto/bfv.rs | 11 +--------- .../fhe/tests/unified_context_integration.rs | 2 +- 36 files changed, 149 insertions(+), 111 deletions(-) diff --git a/crates/fhe-math/benches/ntt.rs b/crates/fhe-math/benches/ntt.rs index ad49a9cb..3697157d 100644 --- a/crates/fhe-math/benches/ntt.rs +++ b/crates/fhe-math/benches/ntt.rs @@ -1,7 +1,4 @@ -// Allow indexing in benchmarks for convenience -#![allow(clippy::indexing_slicing)] -#![allow(missing_docs)] - +#![expect(missing_docs, reason = "examples/benches/tests omit docs by design")] use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main}; use fhe_math::{ntt::NttOperator, zq::Modulus}; use rand::rng; diff --git a/crates/fhe-math/benches/rns.rs b/crates/fhe-math/benches/rns.rs index 64687221..fe1f64a4 100644 --- a/crates/fhe-math/benches/rns.rs +++ b/crates/fhe-math/benches/rns.rs @@ -1,7 +1,4 @@ -// Allow indexing in benchmarks for convenience -#![allow(clippy::indexing_slicing)] -#![allow(missing_docs)] - +#![expect(missing_docs, reason = "examples/benches/tests omit docs by design")] use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main}; use fhe_math::rns::{RnsContext, RnsScaler, ScalingFactor}; use num_bigint::BigUint; diff --git a/crates/fhe-math/benches/rq.rs b/crates/fhe-math/benches/rq.rs index b7bcfdf3..4b5d866a 100644 --- a/crates/fhe-math/benches/rq.rs +++ b/crates/fhe-math/benches/rq.rs @@ -1,7 +1,8 @@ -// Allow indexing in benchmarks for convenience -#![allow(clippy::indexing_slicing)] -#![allow(missing_docs)] - +#![expect(missing_docs, reason = "examples/benches/tests omit docs by design")] +#![expect( + clippy::indexing_slicing, + reason = "performance or example code relies on validated indices" +)] use criterion::measurement::WallTime; use criterion::{BenchmarkGroup, BenchmarkId, Criterion, criterion_group, criterion_main}; use fhe_math::rq::*; diff --git a/crates/fhe-math/benches/zq.rs b/crates/fhe-math/benches/zq.rs index 34e204b5..3ee83fb9 100644 --- a/crates/fhe-math/benches/zq.rs +++ b/crates/fhe-math/benches/zq.rs @@ -1,7 +1,8 @@ -// Allow indexing in benchmarks for convenience -#![allow(clippy::indexing_slicing)] -#![allow(missing_docs)] - +#![expect(missing_docs, reason = "examples/benches/tests omit docs by design")] +#![expect( + clippy::indexing_slicing, + reason = "performance or example code relies on validated indices" +)] use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main}; use fhe_math::zq::Modulus; use rand::rng; diff --git a/crates/fhe-math/src/ntt/native.rs b/crates/fhe-math/src/ntt/native.rs index d8cbedb0..f78e8888 100644 --- a/crates/fhe-math/src/ntt/native.rs +++ b/crates/fhe-math/src/ntt/native.rs @@ -1,6 +1,9 @@ -// Allow indexing in this performance-critical NTT implementation. +// Expect indexing in this performance-critical NTT implementation. // The unsafe blocks already indicate this is performance-sensitive code. -#![allow(clippy::indexing_slicing)] +#![expect( + clippy::indexing_slicing, + reason = "performance or example code relies on validated indices" +)] use crate::zq::Modulus; use itertools::Itertools; diff --git a/crates/fhe-math/src/proto/mod.rs b/crates/fhe-math/src/proto/mod.rs index 83bf65e1..367294cf 100644 --- a/crates/fhe-math/src/proto/mod.rs +++ b/crates/fhe-math/src/proto/mod.rs @@ -1,6 +1,4 @@ //! Protobuf for the `fhe-math` crate. -#![allow(missing_docs)] - /// Protobuf for polynomials. pub mod rq; diff --git a/crates/fhe-math/src/proto/rq.rs b/crates/fhe-math/src/proto/rq.rs index 0d0f6214..ec32b85f 100644 --- a/crates/fhe-math/src/proto/rq.rs +++ b/crates/fhe-math/src/proto/rq.rs @@ -1,6 +1,7 @@ -#![allow(missing_docs)] - -#[allow(clippy::derive_partial_eq_without_eq)] +#[expect( + clippy::derive_partial_eq_without_eq, + reason = "prost-generated types do not need Eq" +)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Rq { #[prost(enumeration = "Representation", tag = "1")] diff --git a/crates/fhe-math/src/rns/mod.rs b/crates/fhe-math/src/rns/mod.rs index ffc4f8f3..359e5701 100644 --- a/crates/fhe-math/src/rns/mod.rs +++ b/crates/fhe-math/src/rns/mod.rs @@ -1,6 +1,9 @@ #![warn(missing_docs, unused_imports)] -// Allow indexing in this performance-critical RNS implementation -#![allow(clippy::indexing_slicing)] +// Expect indexing in this performance-critical RNS implementation +#![expect( + clippy::indexing_slicing, + reason = "performance or example code relies on validated indices" +)] //! Residue-Number System operations. @@ -69,7 +72,10 @@ impl RnsContext { product_dig *= &BigUintDig::from(moduli_u64[i]); } - #[allow(clippy::type_complexity)] + #[expect( + clippy::type_complexity, + reason = "complex tuple is produced by multiunzip" + )] let (moduli, q_tilde, q_tilde_shoup, q_star, garner): ( Vec, Vec, diff --git a/crates/fhe-math/src/rns/scaler.rs b/crates/fhe-math/src/rns/scaler.rs index f295ace2..edced8d8 100644 --- a/crates/fhe-math/src/rns/scaler.rs +++ b/crates/fhe-math/src/rns/scaler.rs @@ -1,6 +1,9 @@ #![warn(missing_docs, unused_imports)] -// Allow indexing in this performance-critical RNS scaler implementation -#![allow(clippy::indexing_slicing)] +// Expect indexing in this performance-critical RNS scaler implementation +#![expect( + clippy::indexing_slicing, + reason = "performance or example code relies on validated indices" +)] //! RNS scaler inspired from Remark 3.2 of . diff --git a/crates/fhe-math/src/rq/convert.rs b/crates/fhe-math/src/rq/convert.rs index 410797ea..a7f9cf38 100644 --- a/crates/fhe-math/src/rq/convert.rs +++ b/crates/fhe-math/src/rq/convert.rs @@ -434,7 +434,7 @@ impl From<&Poly> for Vec { #[cfg(test)] mod tests { - #![allow(clippy::expect_used)] + #![expect(clippy::expect_used, reason = "bounds are validated before use")] use crate::{ Error as CrateError, diff --git a/crates/fhe-math/src/rq/mod.rs b/crates/fhe-math/src/rq/mod.rs index 52a3beaa..f876983f 100644 --- a/crates/fhe-math/src/rq/mod.rs +++ b/crates/fhe-math/src/rq/mod.rs @@ -1,7 +1,10 @@ #![warn(missing_docs, unused_imports)] -// Allow indexing/slicing in this performance-critical polynomial arithmetic module. +// Expect indexing/slicing in this performance-critical polynomial arithmetic module. // This code heavily uses RNS representation and requires fast array access. -#![allow(clippy::indexing_slicing)] +#![expect( + clippy::indexing_slicing, + reason = "performance or example code relies on validated indices" +)] //! Polynomials in R_q\[x\] = (ZZ_q1 x ... x ZZ_qn)\[x\] where the qi's are //! prime moduli in zq. diff --git a/crates/fhe-math/src/rq/ops.rs b/crates/fhe-math/src/rq/ops.rs index 0510b170..8c4a0ac2 100644 --- a/crates/fhe-math/src/rq/ops.rs +++ b/crates/fhe-math/src/rq/ops.rs @@ -110,7 +110,7 @@ impl Sub<&Poly> for &Poly { } impl MulAssign<&Poly> for Poly { - #[allow(clippy::panic)] + #[expect(clippy::panic, reason = "panic indicates violated internal invariant")] fn mul_assign(&mut self, p: &Poly) { assert!(!p.has_lazy_coefficients); assert_ne!( diff --git a/crates/fhe-math/src/zq/mod.rs b/crates/fhe-math/src/zq/mod.rs index efb6b358..69f054a9 100644 --- a/crates/fhe-math/src/zq/mod.rs +++ b/crates/fhe-math/src/zq/mod.rs @@ -1118,7 +1118,6 @@ mod tests { let ntests = 100; let mut rng = rand::rng(); - #[allow(clippy::single_element_loop)] for p in [4611686018326724609] { let q = Modulus::new(p).unwrap(); assert!(primes::supports_opt(p)); diff --git a/crates/fhe-util/src/lib.rs b/crates/fhe-util/src/lib.rs index 85f00d9e..94d853be 100644 --- a/crates/fhe-util/src/lib.rs +++ b/crates/fhe-util/src/lib.rs @@ -56,7 +56,7 @@ pub fn sample_vec_cbd( /// Transcodes a vector of u64 of `nbits`-bit numbers into a vector of bytes. #[must_use] -#[allow(clippy::expect_used)] +#[expect(clippy::expect_used, reason = "bounds are validated before use")] pub fn transcode_to_bytes(a: &[u64], nbits: usize) -> Vec { assert!(0 < nbits && nbits <= 64); @@ -96,7 +96,7 @@ pub fn transcode_to_bytes(a: &[u64], nbits: usize) -> Vec { /// Transcodes a vector of u8 into a vector of u64 of `nbits`-bit numbers. #[must_use] -#[allow(clippy::expect_used)] +#[expect(clippy::expect_used, reason = "bounds are validated before use")] pub fn transcode_from_bytes(b: &[u8], nbits: usize) -> Vec { assert!(0 < nbits && nbits <= 64); let mask = (u64::MAX >> (64 - nbits)) as u128; @@ -135,7 +135,7 @@ pub fn transcode_from_bytes(b: &[u8], nbits: usize) -> Vec { /// Transcodes a vector of u64 of `input_nbits`-bit numbers into a vector of u64 /// of `output_nbits`-bit numbers. #[must_use] -#[allow(clippy::expect_used)] +#[expect(clippy::expect_used, reason = "bounds are validated before use")] pub fn transcode_bidirectional(a: &[u64], input_nbits: usize, output_nbits: usize) -> Vec { assert!(0 < input_nbits && input_nbits <= 64); assert!(0 < output_nbits && output_nbits <= 64); @@ -196,8 +196,11 @@ pub fn variance(values: &[T]) -> f64 { #[cfg(test)] mod tests { - // Allow indexing in tests for convenience - #![allow(clippy::indexing_slicing)] + // Expect indexing in tests for convenience + #![expect( + clippy::indexing_slicing, + reason = "performance or example code relies on validated indices" + )] use itertools::Itertools; use rand::RngCore; @@ -291,6 +294,15 @@ mod tests { assert_eq!(&decoded[..input.len()], input); } + #[test] + fn transcode_empty_roundtrip() { + let input: Vec = Vec::new(); + let bytes = transcode_to_bytes(&input, 8); + assert!(bytes.is_empty()); + let decoded = transcode_from_bytes(&bytes, 8); + assert!(decoded.is_empty()); + } + #[test] fn inv_kats() { // KATs for inversion generated in Sage using the following code. diff --git a/crates/fhe/benches/bfv.rs b/crates/fhe/benches/bfv.rs index a8187ca0..b1b0b2b1 100644 --- a/crates/fhe/benches/bfv.rs +++ b/crates/fhe/benches/bfv.rs @@ -1,6 +1,9 @@ -// Allow indexing in benchmarks for convenience -#![allow(clippy::indexing_slicing)] -#![allow(missing_docs)] +// Expect indexing in benchmarks for convenience +#![expect(missing_docs, reason = "examples/benches/tests omit docs by design")] +#![expect( + clippy::indexing_slicing, + reason = "performance or example code relies on validated indices" +)] use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main}; use fhe::bfv::{ diff --git a/crates/fhe/benches/bfv_optimized_ops.rs b/crates/fhe/benches/bfv_optimized_ops.rs index 0190dafb..dbe8d9d4 100644 --- a/crates/fhe/benches/bfv_optimized_ops.rs +++ b/crates/fhe/benches/bfv_optimized_ops.rs @@ -1,6 +1,5 @@ -// Allow indexing in benchmarks for convenience -#![allow(clippy::indexing_slicing)] -#![allow(missing_docs)] +// Expect indexing in benchmarks for convenience +#![expect(missing_docs, reason = "examples/benches/tests omit docs by design")] use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main}; use fhe::bfv::{BfvParameters, Ciphertext, Encoding, Plaintext, SecretKey, dot_product_scalar}; diff --git a/crates/fhe/benches/bfv_rgsw.rs b/crates/fhe/benches/bfv_rgsw.rs index d2734f6f..9910b1b1 100644 --- a/crates/fhe/benches/bfv_rgsw.rs +++ b/crates/fhe/benches/bfv_rgsw.rs @@ -1,6 +1,5 @@ -// Allow indexing in benchmarks for convenience -#![allow(clippy::indexing_slicing)] -#![allow(missing_docs)] +// Expect indexing in benchmarks for convenience +#![expect(missing_docs, reason = "examples/benches/tests omit docs by design")] use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main}; use fhe::bfv::{BfvParameters, Ciphertext, Encoding, Plaintext, RGSWCiphertext, SecretKey}; diff --git a/crates/fhe/examples/bfv_basic.rs b/crates/fhe/examples/bfv_basic.rs index 7d26d997..ed1cf566 100644 --- a/crates/fhe/examples/bfv_basic.rs +++ b/crates/fhe/examples/bfv_basic.rs @@ -1,6 +1,9 @@ -// Allow indexing in examples for simplicity -#![allow(clippy::indexing_slicing)] -#![allow(missing_docs)] +// Expect indexing in examples for simplicity +#![expect(missing_docs, reason = "examples/benches/tests omit docs by design")] +#![expect( + clippy::indexing_slicing, + reason = "performance or example code relies on validated indices" +)] use std::error::Error; diff --git a/crates/fhe/examples/bfv_ops.rs b/crates/fhe/examples/bfv_ops.rs index 3b85cc53..5658642f 100644 --- a/crates/fhe/examples/bfv_ops.rs +++ b/crates/fhe/examples/bfv_ops.rs @@ -1,6 +1,9 @@ -// Allow indexing in examples for simplicity -#![allow(clippy::indexing_slicing)] -#![allow(missing_docs)] +// Expect indexing in examples for simplicity +#![expect(missing_docs, reason = "examples/benches/tests omit docs by design")] +#![expect( + clippy::indexing_slicing, + reason = "performance or example code relies on validated indices" +)] mod util; diff --git a/crates/fhe/examples/mulpir.rs b/crates/fhe/examples/mulpir.rs index 209c1bce..da40f72f 100644 --- a/crates/fhe/examples/mulpir.rs +++ b/crates/fhe/examples/mulpir.rs @@ -1,6 +1,9 @@ -// Allow indexing in examples for simplicity -#![allow(clippy::indexing_slicing)] -#![allow(missing_docs)] +// Expect indexing in examples for simplicity +#![expect(missing_docs, reason = "examples/benches/tests omit docs by design")] +#![expect( + clippy::indexing_slicing, + reason = "performance or example code relies on validated indices" +)] // Implementation of MulPIR using the `fhe` crate. // diff --git a/crates/fhe/examples/pir.rs b/crates/fhe/examples/pir.rs index e75dab42..07b2dab3 100644 --- a/crates/fhe/examples/pir.rs +++ b/crates/fhe/examples/pir.rs @@ -1,9 +1,9 @@ -// Allow indexing in examples for simplicity -#![allow(clippy::indexing_slicing)] -#![allow(missing_docs)] +//! CLI configuration for PIR example runs. +// Expect indexing in examples for simplicity use clap::Parser; +/// Command-line arguments for configuring a PIR example run. #[derive(Parser)] pub struct Cli { #[arg( @@ -11,6 +11,7 @@ pub struct Cli { help = "The number of elements in the database", default_value = "65536" )] + /// Number of elements in the database. pub database_size: usize, #[arg( @@ -18,6 +19,7 @@ pub struct Cli { help = "The size of each database element", default_value = "1024" )] + /// Size in bytes of each database element. pub element_size: usize, } diff --git a/crates/fhe/examples/rgsw.rs b/crates/fhe/examples/rgsw.rs index 1749b469..32c31a2c 100644 --- a/crates/fhe/examples/rgsw.rs +++ b/crates/fhe/examples/rgsw.rs @@ -1,6 +1,9 @@ -// Allow indexing in examples for simplicity -#![allow(clippy::indexing_slicing)] -#![allow(missing_docs)] +// Expect indexing in examples for simplicity +#![expect(missing_docs, reason = "examples/benches/tests omit docs by design")] +#![expect( + clippy::indexing_slicing, + reason = "performance or example code relies on validated indices" +)] use std::error::Error; diff --git a/crates/fhe/examples/sealpir.rs b/crates/fhe/examples/sealpir.rs index 74910646..8ec01feb 100644 --- a/crates/fhe/examples/sealpir.rs +++ b/crates/fhe/examples/sealpir.rs @@ -1,6 +1,9 @@ -// Allow indexing in examples for simplicity -#![allow(clippy::indexing_slicing)] -#![allow(missing_docs)] +// Expect indexing in examples for simplicity +#![expect(missing_docs, reason = "examples/benches/tests omit docs by design")] +#![expect( + clippy::indexing_slicing, + reason = "performance or example code relies on validated indices" +)] // Implementation of SealPIR using the `fhe` crate. // diff --git a/crates/fhe/examples/util.rs b/crates/fhe/examples/util.rs index 11ff230a..f31ea448 100644 --- a/crates/fhe/examples/util.rs +++ b/crates/fhe/examples/util.rs @@ -1,9 +1,14 @@ -// Allow indexing in examples for simplicity -#![allow(clippy::indexing_slicing)] -#![allow(missing_docs)] +// Expect indexing in examples for simplicity +#![expect( + clippy::indexing_slicing, + reason = "performance or example code relies on validated indices" +)] //! Utility functions for the examples +// Example utilities are shared across multiple binaries, so some items are unused per-target. +#![allow(dead_code, unused_imports, unused_macros)] + use fhe::bfv; use fhe_traits::FheEncoder; use fhe_util::transcode_from_bytes; @@ -11,7 +16,6 @@ use std::{cmp::min, fmt, sync::Arc, time::Duration}; /// Macros to time code and display a human-readable duration. pub mod timeit { - #[allow(unused_macros)] macro_rules! timeit_n { ($name:expr, $loops:expr, $code:expr) => {{ use util::DisplayDuration; @@ -29,7 +33,6 @@ pub mod timeit { }}; } - #[allow(unused_macros)] macro_rules! timeit { ($name:expr, $code:expr) => {{ use util::DisplayDuration; @@ -40,9 +43,7 @@ pub mod timeit { }}; } - #[allow(unused_imports)] pub(crate) use timeit; - #[allow(unused_imports)] pub(crate) use timeit_n; } @@ -69,7 +70,6 @@ impl fmt::Display for DisplayDuration { /// Generate a database of elements of the form [i || 0...0] where i is the 4B /// little endian encoding of the index. When the element size is less than 4B, /// the encoding is truncated. -#[allow(dead_code)] #[must_use] pub fn generate_database(database_size: usize, elements_size: usize) -> Vec> { assert!(database_size > 0 && elements_size > 0); @@ -81,7 +81,7 @@ pub fn generate_database(database_size: usize, elements_size: usize) -> Vec], @@ -132,5 +133,4 @@ pub fn encode_database( (preprocessed_database, (dimension_1, dimension_2)) } -#[allow(dead_code)] fn main() {} diff --git a/crates/fhe/examples/voting.rs b/crates/fhe/examples/voting.rs index b84adae5..784035f0 100644 --- a/crates/fhe/examples/voting.rs +++ b/crates/fhe/examples/voting.rs @@ -1,6 +1,9 @@ -// Allow indexing in examples for simplicity -#![allow(clippy::indexing_slicing)] -#![allow(missing_docs)] +// Expect indexing in examples for simplicity +#![expect(missing_docs, reason = "examples/benches/tests omit docs by design")] +#![expect( + clippy::indexing_slicing, + reason = "performance or example code relies on validated indices" +)] // Implementation of multiparty voting using the `fhe` crate. @@ -128,7 +131,6 @@ fn main() -> Result<(), Box> { let mut votes_encrypted = Vec::with_capacity(num_voters); let mut _i = 0; timeit_n!("Vote casting (per voter)", num_voters as u32, { - #[allow(unused_assignments)] let pt = Plaintext::try_encode(&[votes[_i]], Encoding::poly(), ¶ms)?; let ct = pk.try_encrypt(&pt, &mut rng)?; votes_encrypted.push(ct); diff --git a/crates/fhe/src/bfv/ciphertext.rs b/crates/fhe/src/bfv/ciphertext.rs index fc64184e..fc755036 100644 --- a/crates/fhe/src/bfv/ciphertext.rs +++ b/crates/fhe/src/bfv/ciphertext.rs @@ -47,7 +47,7 @@ impl Ciphertext { /// Create a ciphertext from a vector of polynomials. /// A ciphertext must contain at least two polynomials, and all polynomials /// must be in Ntt representation and with the same context. - #[allow(clippy::expect_used)] + #[expect(clippy::expect_used, reason = "bounds are validated before use")] pub fn new(c: Vec, par: &Arc) -> Result { if c.len() < 2 { return Err(Error::TooFewValues { @@ -359,7 +359,7 @@ mod tests { } #[test] - #[allow(clippy::panic)] + #[expect(clippy::panic, reason = "panic indicates violated internal invariant")] fn switch_to_level_invalid() -> Result<(), Box> { let mut rng = rng(); let params = BfvParameters::default_arc(2, 16); diff --git a/crates/fhe/src/bfv/context/chain.rs b/crates/fhe/src/bfv/context/chain.rs index 665e7c5f..a07a642d 100644 --- a/crates/fhe/src/bfv/context/chain.rs +++ b/crates/fhe/src/bfv/context/chain.rs @@ -132,7 +132,7 @@ impl ContextLevel { } /// Access multiplication parameters for this level - #[allow(clippy::expect_used)] + #[expect(clippy::expect_used, reason = "bounds are validated before use")] pub(crate) fn mul_params(&self) -> &MultiplicationParameters { self.mul_params .get() diff --git a/crates/fhe/src/bfv/keys/evaluation_key.rs b/crates/fhe/src/bfv/keys/evaluation_key.rs index 19aa82fa..c1f225eb 100644 --- a/crates/fhe/src/bfv/keys/evaluation_key.rs +++ b/crates/fhe/src/bfv/keys/evaluation_key.rs @@ -289,7 +289,6 @@ impl EvaluationKeyBuilder { } /// Allow expansion by this evaluation key. - #[allow(unused_must_use)] pub fn enable_expansion(&mut self, level: usize) -> Result<&mut Self> { if level >= 64 - self.sk.par.degree().leading_zeros() as usize { Err(Error::DefaultError("Invalid level 2".to_string())) @@ -300,14 +299,12 @@ impl EvaluationKeyBuilder { } /// Allow this evaluation key to compute homomorphic inner sums. - #[allow(unused_must_use)] pub fn enable_inner_sum(&mut self) -> Result<&mut Self> { self.inner_sum = true; Ok(self) } /// Allow this evaluation key to homomorphically rotate the plaintext rows. - #[allow(unused_must_use)] pub fn enable_row_rotation(&mut self) -> Result<&mut Self> { self.row_rotation = true; Ok(self) @@ -315,7 +312,6 @@ impl EvaluationKeyBuilder { /// Allow this evaluation key to homomorphically rotate the plaintext /// columns. - #[allow(unused_must_use)] pub fn enable_column_rotation(&mut self, i: usize) -> Result<&mut Self> { if let Some(exp) = self.rot_to_gk_exponent.get(&i) { self.column_rotation.insert(*exp); diff --git a/crates/fhe/src/bfv/keys/relinearization_key.rs b/crates/fhe/src/bfv/keys/relinearization_key.rs index e51099ba..00d43ae7 100644 --- a/crates/fhe/src/bfv/keys/relinearization_key.rs +++ b/crates/fhe/src/bfv/keys/relinearization_key.rs @@ -85,7 +85,6 @@ impl RelinearizationKey { let mut c2 = ct[2].clone(); c2.change_representation(Representation::PowerBasis); - #[allow(unused_mut)] let (mut c0, mut c1) = self.relinearizes_poly(&c2)?; if c0.ctx() != ct[0].ctx() { diff --git a/crates/fhe/src/bfv/mod.rs b/crates/fhe/src/bfv/mod.rs index e1b6d072..fec4755b 100644 --- a/crates/fhe/src/bfv/mod.rs +++ b/crates/fhe/src/bfv/mod.rs @@ -1,6 +1,9 @@ #![warn(missing_docs, unused_imports)] -// Allow indexing in BFV cryptographic operations for performance -#![allow(clippy::indexing_slicing)] +// Expect indexing in BFV cryptographic operations for performance +#![expect( + clippy::indexing_slicing, + reason = "performance or example code relies on validated indices" +)] //! The Brakerski-Fan-Vercauteren homomorphic encryption scheme diff --git a/crates/fhe/src/bfv/ops/mul.rs b/crates/fhe/src/bfv/ops/mul.rs index 36258565..993aedb9 100644 --- a/crates/fhe/src/bfv/ops/mul.rs +++ b/crates/fhe/src/bfv/ops/mul.rs @@ -197,7 +197,6 @@ impl Multiplicator { // Relinearize if let Some(rk) = self.rk.as_ref() { - #[allow(unused_mut)] let (mut c0r, mut c1r) = rk.relinearizes_poly(&c[2])?; if c0r.ctx() != c[0].ctx() { diff --git a/crates/fhe/src/bfv/parameters.rs b/crates/fhe/src/bfv/parameters.rs index 63407ef1..4ca6b9c6 100644 --- a/crates/fhe/src/bfv/parameters.rs +++ b/crates/fhe/src/bfv/parameters.rs @@ -248,7 +248,7 @@ impl BfvParameters { #[cfg(test)] /// Returns default parameters for tests. #[must_use] - #[allow(clippy::panic)] + #[expect(clippy::panic, reason = "panic indicates violated internal invariant")] pub fn default_arc(num_moduli: usize, degree: usize) -> Arc { if !degree.is_power_of_two() || degree < 8 { panic!("Invalid degree"); @@ -274,7 +274,10 @@ pub struct BfvParametersBuilder { impl BfvParametersBuilder { /// Creates a new instance of the builder - #[allow(clippy::new_without_default)] + #[expect( + clippy::new_without_default, + reason = "builder requires explicit configuration" + )] #[must_use] pub fn new() -> Self { Self { @@ -712,7 +715,7 @@ mod tests { let result = BfvParameters::default_parameters_128(10); assert!(result.is_err()); - #[allow(clippy::panic)] + #[expect(clippy::panic, reason = "panic indicates violated internal invariant")] match result { Err(e) => { let error_string = format!("{e}"); diff --git a/crates/fhe/src/errors.rs b/crates/fhe/src/errors.rs index 719830c4..9f4c79b4 100644 --- a/crates/fhe/src/errors.rs +++ b/crates/fhe/src/errors.rs @@ -1,4 +1,7 @@ -#![allow(missing_docs)] +#![expect( + missing_docs, + reason = "error enums rely on variant docs and error messages" +)] use thiserror::Error; @@ -7,7 +10,7 @@ pub type Result = std::result::Result; /// Enum encapsulating all the possible errors from this library. #[derive(Debug, Error, PartialEq, Eq)] -#[allow(missing_docs)] +#[expect(missing_docs, reason = "error variants are documented inline")] #[non_exhaustive] pub enum Error { /// Indicates that an error from the underlying mathematical library was @@ -164,7 +167,7 @@ impl Error { /// Separate enum for errors arising from serialization. #[derive(Debug, Error, PartialEq, Eq)] -#[allow(missing_docs)] +#[expect(missing_docs, reason = "error variants are documented inline")] #[non_exhaustive] pub enum SerializationError { /// Indicates polynomial context was not found during deserialization @@ -219,7 +222,7 @@ impl From for SerializationError { /// Separate enum to indicate parameters-related errors. #[derive(Debug, Error, PartialEq, Eq)] -#[allow(missing_docs)] +#[expect(missing_docs, reason = "error variants are documented inline")] #[non_exhaustive] pub enum ParametersError { /// Indicates that the degree is invalid. diff --git a/crates/fhe/src/mbfv/mod.rs b/crates/fhe/src/mbfv/mod.rs index b2fd12bf..062128c4 100644 --- a/crates/fhe/src/mbfv/mod.rs +++ b/crates/fhe/src/mbfv/mod.rs @@ -1,5 +1,8 @@ -// Allow indexing in multiparty BFV cryptographic operations for performance -#![allow(clippy::indexing_slicing)] +// Expect indexing in multiparty BFV cryptographic operations for performance +#![expect( + clippy::indexing_slicing, + reason = "performance or example code relies on validated indices" +)] //! The Multiparty BFV scheme, as described by Christian Mouchet et. al. //! in [Multiparty Homomorphic Encryption from Ring-Learning-with-Errors](https://eprint.iacr.org/2020/304.pdf). diff --git a/crates/fhe/src/proto/bfv.rs b/crates/fhe/src/proto/bfv.rs index 8c790d05..0c439d95 100644 --- a/crates/fhe/src/proto/bfv.rs +++ b/crates/fhe/src/proto/bfv.rs @@ -1,6 +1,5 @@ -#![allow(missing_docs)] +#![expect(missing_docs, reason = "prost-generated types omit docs")] -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Ciphertext { #[prost(bytes = "vec", repeated, tag = "1")] @@ -10,7 +9,6 @@ pub struct Ciphertext { #[prost(uint32, tag = "3")] pub level: u32, } -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct RgswCiphertext { #[prost(message, optional, tag = "1")] @@ -18,7 +16,6 @@ pub struct RgswCiphertext { #[prost(message, optional, tag = "2")] pub ksk1: ::core::option::Option, } -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct KeySwitchingKey { #[prost(bytes = "vec", repeated, tag = "1")] @@ -34,13 +31,11 @@ pub struct KeySwitchingKey { #[prost(uint32, tag = "6")] pub log_base: u32, } -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct RelinearizationKey { #[prost(message, optional, tag = "1")] pub ksk: ::core::option::Option, } -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct GaloisKey { #[prost(message, optional, tag = "1")] @@ -48,7 +43,6 @@ pub struct GaloisKey { #[prost(uint32, tag = "2")] pub exponent: u32, } -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct EvaluationKey { #[prost(message, repeated, tag = "2")] @@ -58,7 +52,6 @@ pub struct EvaluationKey { #[prost(uint32, tag = "4")] pub evaluation_key_level: u32, } -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Parameters { #[prost(uint32, tag = "1")] @@ -70,13 +63,11 @@ pub struct Parameters { #[prost(uint32, tag = "4")] pub variance: u32, } -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct PublicKey { #[prost(message, optional, tag = "1")] pub c: ::core::option::Option, } -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct SecretKey { #[prost(sint64, repeated, tag = "1")] diff --git a/crates/fhe/tests/unified_context_integration.rs b/crates/fhe/tests/unified_context_integration.rs index c2e96bab..e813e301 100644 --- a/crates/fhe/tests/unified_context_integration.rs +++ b/crates/fhe/tests/unified_context_integration.rs @@ -1,5 +1,5 @@ // Integration test to verify the unified context management API works correctly -#![allow(missing_docs)] +#![expect(missing_docs, reason = "examples/benches/tests omit docs by design")] use fhe::bfv::BfvParametersBuilder;