From 682517c055405442a84bac585aaf9534a931362a Mon Sep 17 00:00:00 2001 From: jfdreis Date: Tue, 2 Dec 2025 15:23:49 +0000 Subject: [PATCH] Add as_conversions lint warning to crypto crate --- Cargo.toml | 4 + crates/crypto/src/commitments/kzg.rs | 6 +- crates/crypto/src/hash/monolith/mod.rs | 75 +++++++++++++------ .../rescue_prime/rescue_prime_optimized.rs | 4 +- crates/crypto/src/hash/rescue_prime/utils.rs | 14 ++-- crates/crypto/src/hash/sha3/mod.rs | 43 +++++++---- crates/crypto/src/lib.rs | 1 + crates/math/src/circle/polynomial.rs | 9 ++- crates/math/src/circle/twiddles.rs | 2 + crates/math/src/fft/errors.rs | 3 + crates/math/src/field/element.rs | 9 ++- crates/math/src/field/errors.rs | 2 + 12 files changed, 119 insertions(+), 53 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0e9a4acc2..a6cf442e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,3 +60,7 @@ winter-crypto = { git = "https://github.com/lambdaclass/winterfell-for-lambdawor lto = true codegen-units = 1 opt-level = 3 + +[workspace.lints.clippy] +restriction = "warn" +as_conversions = "warn" \ No newline at end of file diff --git a/crates/crypto/src/commitments/kzg.rs b/crates/crypto/src/commitments/kzg.rs index ea3ee6721..c720b1a5c 100644 --- a/crates/crypto/src/commitments/kzg.rs +++ b/crates/crypto/src/commitments/kzg.rs @@ -322,10 +322,8 @@ mod tests { }); let g1 = BLS12381Curve::generator(); let g2 = BLS12381TwistCurve::generator(); - let powers_main_group: Vec = (0..100) - .map(|exponent| { - g1.operate_with_self(toxic_waste.pow(exponent as u128).representative()) - }) + let powers_main_group: Vec = (0..100u128) + .map(|exponent| g1.operate_with_self(toxic_waste.pow(exponent).representative())) .collect(); let powers_secondary_group = [ g2.clone(), diff --git a/crates/crypto/src/hash/monolith/mod.rs b/crates/crypto/src/hash/monolith/mod.rs index 26b624349..050ea3655 100644 --- a/crates/crypto/src/hash/monolith/mod.rs +++ b/crates/crypto/src/hash/monolith/mod.rs @@ -38,28 +38,35 @@ impl MonolithMersenne31 Vec> { + fn instantiate_round_constants() -> Result>, String> { let mut shake = Shake128::default(); shake.update("Monolith".as_bytes()); - shake.update(&[WIDTH as u8, (NUM_FULL_ROUNDS + 1) as u8]); + let num_full_round_plus_one = + u8::try_from(NUM_FULL_ROUNDS + 1).map_err(|e| format!("size conversion error: {e}"))?; + shake.update(&[ + u8::try_from(WIDTH).expect("as 8<=WIDTH<=24, this should never fail"), + num_full_round_plus_one, + ]); shake.update(&MERSENNE_31_PRIME_FIELD_ORDER.to_le_bytes()); shake.update(&[8, 8, 8, 7]); let mut shake_finalized = shake.finalize_xof(); - random_matrix(&mut shake_finalized, NUM_FULL_ROUNDS, WIDTH) + Ok(random_matrix(&mut shake_finalized, NUM_FULL_ROUNDS, WIDTH)) } fn instantiate_lookup1() -> Vec { (0..=u16::MAX) .map(|i| { - let hi = (i >> 8) as u8; - let lo = i as u8; - ((Self::s_box(hi) as u16) << 8) | Self::s_box(lo) as u16 + let hi = + u8::try_from(i >> 8).expect("as (i>>8) <= u8::MAX this should never fail"); + let lo = u8::try_from(i & 0xFF) + .expect("as (i & 0xFF) <= u8::MAX this should never fail"); + (u16::from(Self::s_box(hi)) << 8) | u16::from(Self::s_box(lo)) }) .collect() } @@ -67,9 +74,11 @@ impl MonolithMersenne31 Vec { (0..(1 << 15)) .map(|i| { - let hi = (i >> 8) as u8; - let lo: u8 = i as u8; - ((Self::final_s_box(hi) as u16) << 8) | Self::s_box(lo) as u16 + let hi = + u8::try_from(i >> 8).expect("as (i>>8) <= u8::MAX and this should never fail"); + let lo = u8::try_from(i & 0xFF) + .expect("as (i & 0xFF) <= u8::MAX this should never fail"); + ((u16::from(Self::final_s_box(hi))) << 8) | u16::from(Self::s_box(lo)) }) .collect() } @@ -89,39 +98,55 @@ impl MonolithMersenne31) { - self.concrete(state); + self.concrete(state).unwrap(); for round in 0..NUM_FULL_ROUNDS { self.bars(state); Self::bricks(state); - self.concrete(state); + self.concrete(state).unwrap(); Self::add_round_constants(state, &self.round_constants[round]); } self.bars(state); Self::bricks(state); - self.concrete(state); + self.concrete(state).unwrap(); } // MDS matrix - fn concrete(&self, state: &mut Vec) { + fn concrete(&self, state: &mut Vec) -> Result<(), Box> { *state = if WIDTH == 16 { Self::apply_circulant(&mut MATRIX_CIRC_MDS_16_MERSENNE31_MONOLITH.clone(), state) } else { let mut shake = Shake128::default(); shake.update("Monolith".as_bytes()); - shake.update(&[WIDTH as u8, (NUM_FULL_ROUNDS + 1) as u8]); + let num_full_round_plus_one = u8::try_from(NUM_FULL_ROUNDS + 1) + .map_err(|e| format!("size conversion error: {e}"))?; + shake.update(&[ + u8::try_from(WIDTH).expect("as 8<=WIDTH<=24 this should never fail"), + num_full_round_plus_one, + ]); shake.update(&MERSENNE_31_PRIME_FIELD_ORDER.to_le_bytes()); shake.update(&[16, 15]); shake.update("MDS".as_bytes()); let mut shake_finalized = shake.finalize_xof(); Self::apply_cauchy_mds_matrix(&mut shake_finalized, state) }; + Ok(()) } // S-box lookups fn bars(&self, state: &mut [u32]) { for state in state.iter_mut().take(NUM_BARS) { - *state = ((self.lookup2[(*state >> 16) as u16 as usize] as u32) << 16) - | (self.lookup1[*state as u16 as usize] as u32); + *state = ((u32::from( + self.lookup2[usize::from( + u16::try_from((*state >> 16) & 0xFFFF) + .expect("as (*state >> 16) & 0xFFFF <= u16::MAX this should never fail"), + )], + )) << 16) + | (u32::from( + self.lookup1[usize::from( + u16::try_from(*state & 0xFFFF) + .expect("as *state & 0xFFFF <= u16::MAX this should never fail"), + )], + )); } } @@ -153,7 +178,7 @@ impl MonolithMersenne31 Vec { - (0..width).map(|i| F::from_base_type(i as u32)).collect() + (0..width) + .map(|i| { + F::from_base_type(u32::try_from(i).expect("as 8<=WIDTH<=24 this should never fail")) + }) + .collect() } #[test] fn from_plonky3_concrete_width_16() { let mut input = get_test_input(16); - MonolithMersenne31::<16, 5>::new().concrete(&mut input); + MonolithMersenne31::<16, 5>::new() + .concrete(&mut input) + .expect("as WIDTH = 16 this never fails"); assert_eq!( input, [ @@ -202,7 +233,9 @@ mod tests { #[test] fn from_plonky3_concrete_width_12() { let mut input = get_test_input(12); - MonolithMersenne31::<12, 5>::new().concrete(&mut input); + MonolithMersenne31::<12, 5>::new() + .concrete(&mut input) + .expect("as WIDTH = 12 this never fails"); assert_eq!( input, [ diff --git a/crates/crypto/src/hash/rescue_prime/rescue_prime_optimized.rs b/crates/crypto/src/hash/rescue_prime/rescue_prime_optimized.rs index a8956c5c9..cce480b38 100644 --- a/crates/crypto/src/hash/rescue_prime/rescue_prime_optimized.rs +++ b/crates/crypto/src/hash/rescue_prime/rescue_prime_optimized.rs @@ -111,11 +111,11 @@ impl RescuePrimeOptimized { }; let mds_vector = self.mds_vector.as_slice(); - let mds_ntt = ntt(mds_vector, omega); + let mds_ntt = ntt(mds_vector, omega)?; let state_rev: Vec = iter::once(state[0]) .chain(state[1..].iter().rev().cloned()) .collect(); - let state_ntt = ntt(&state_rev, omega); + let state_ntt = ntt(&state_rev, omega)?; let mut product_ntt = vec![Fp::zero(); m]; for i in 0..m { diff --git a/crates/crypto/src/hash/rescue_prime/utils.rs b/crates/crypto/src/hash/rescue_prime/utils.rs index ba17341bc..516d579bb 100644 --- a/crates/crypto/src/hash/rescue_prime/utils.rs +++ b/crates/crypto/src/hash/rescue_prime/utils.rs @@ -20,20 +20,22 @@ pub fn bytes_to_field_elements(input: &[u8]) -> Vec { .collect() } -pub fn ntt(input: &[Fp], omega: Fp) -> Vec { - (0..input.len()) +pub fn ntt(input: &[Fp], omega: Fp) -> Result, FieldError> { + let input_64 = u64::try_from(input.len()).map_err(|_| FieldError::ConversionError)?; + Ok((0..input_64) .map(|i| { input.iter().enumerate().fold(Fp::zero(), |acc, (j, val)| { - acc + *val * omega.pow((i * j) as u64) + let j = u64::try_from(j).expect("as j < input_64 this should never fail"); + acc + *val * omega.pow(i * j) }) }) - .collect() + .collect()) } pub fn intt(input: &[Fp], omega_inv: Fp) -> Result, FieldError> { - let n = input.len() as u64; + let n = u64::try_from(input.len()).map_err(|_| FieldError::ConversionError)?; let inv_n = Fp::from(n).inv()?; - let transformed = ntt(input, omega_inv); + let transformed = ntt(input, omega_inv)?; Ok(transformed.into_iter().map(|val| val * inv_n).collect()) } diff --git a/crates/crypto/src/hash/sha3/mod.rs b/crates/crypto/src/hash/sha3/mod.rs index 9404e78f3..98dbaae0b 100644 --- a/crates/crypto/src/hash/sha3/mod.rs +++ b/crates/crypto/src/hash/sha3/mod.rs @@ -14,52 +14,65 @@ impl Sha3Hasher { } pub fn expand_message(msg: &[u8], dst: &[u8], len_in_bytes: u64) -> Result, String> { - let b_in_bytes = Sha3_256::output_size() as u64; + let b_in_bytes = u64::try_from(Sha3_256::output_size()) + .expect("Sha3_256::output_size() <= u64::MAX this should never fail"); let ell = len_in_bytes.div_ceil(b_in_bytes); if ell > 255 { return Err("Abort".to_string()); } - - let dst_prime: Vec = [dst, &Self::i2osp(dst.len() as u64, 1)].concat(); - let z_pad = Self::i2osp(0, 64); - let l_i_b_str = Self::i2osp(len_in_bytes, 2); + let dst_64 = u64::try_from(dst.len()).map_err(|e| format!("size conversion error: {e}"))?; + let dst_prime: Vec = [dst, &Self::i2osp(dst_64, 1)?].concat(); + let z_pad = Self::i2osp(0, 64)?; + let l_i_b_str = Self::i2osp(len_in_bytes, 2)?; let msg_prime = [ z_pad, msg.to_vec(), l_i_b_str, - Self::i2osp(0, 1), + Self::i2osp(0, 1)?, dst_prime.clone(), ] .concat(); let b_0: Vec = Sha3_256::digest(msg_prime).to_vec(); - let a = [b_0.clone(), Self::i2osp(1, 1), dst_prime.clone()].concat(); + let a = [b_0.clone(), Self::i2osp(1, 1)?, dst_prime.clone()].concat(); let b_1 = Sha3_256::digest(a).to_vec(); - let mut b_vals = Vec::>::with_capacity(ell as usize); + let mut b_vals = Vec::>::with_capacity( + usize::try_from(ell).expect("as 0 <=ell<= 255 this should never fail"), + ); b_vals.push(b_1); for idx in 1..ell { - let aux = Self::strxor(&b_0, &b_vals[idx as usize - 1]); - let b_i = [aux, Self::i2osp(idx, 1), dst_prime.clone()].concat(); + let aux = Self::strxor( + &b_0, + &b_vals + [usize::try_from(idx).expect("as idx < ell<= 256 this should never fail") - 1], + ); + let b_i = [aux, Self::i2osp(idx, 1)?, dst_prime.clone()].concat(); b_vals.push(Sha3_256::digest(b_i).to_vec()); } let mut b_vals = b_vals.concat(); - b_vals.truncate(len_in_bytes as usize); + b_vals.truncate( + usize::try_from(len_in_bytes).map_err(|e| format!("size conversion error: {e}"))?, + ); Ok(b_vals) } - fn i2osp(x: u64, length: u64) -> Vec { + fn i2osp(x: u64, length: u64) -> Result, String> { let mut x_aux = x; let mut digits = Vec::new(); while x_aux != 0 { - digits.push((x_aux % 256) as u8); + digits.push( + u8::try_from(x_aux % 256) + .expect("as (x_aux % 256) <= u8::MAX this should never fail"), + ); x_aux /= 256; } - digits.resize(length as usize, 0); + let length = usize::try_from(length).map_err(|e| format!("size conversion error: {e}"))?; + digits.resize(length, 0); digits.reverse(); - digits + Ok(digits) } fn strxor(a: &[u8], b: &[u8]) -> Vec { diff --git a/crates/crypto/src/lib.rs b/crates/crypto/src/lib.rs index 5e3d81162..281e5c619 100644 --- a/crates/crypto/src/lib.rs +++ b/crates/crypto/src/lib.rs @@ -1,3 +1,4 @@ +#![warn(clippy::as_conversions)] #![allow(clippy::op_ref)] #![cfg_attr(not(feature = "std"), no_std)] #[macro_use] diff --git a/crates/math/src/circle/polynomial.rs b/crates/math/src/circle/polynomial.rs index 109ed4e04..903baebbd 100644 --- a/crates/math/src/circle/polynomial.rs +++ b/crates/math/src/circle/polynomial.rs @@ -5,6 +5,7 @@ use super::{ cosets::Coset, twiddles::{get_twiddles, TwiddlesConfig}, }; +#[cfg(feature = "alloc")] use crate::{ fft::cpu::bit_reversing::in_place_bit_reverse_permute, field::{element::FieldElement, fields::mersenne31::field::Mersenne31Field}, @@ -66,9 +67,11 @@ pub fn interpolate_cfft( // The icfft returns all the coefficients multiplied by 2^n, the length of the evaluations. // So we multiply every element that outputs the icfft by the inverse of 2^n to get the actual coefficients. // Note that this `unwrap` will never panic because eval.len() != 0. - let factor = (FieldElement::::from(eval.len() as u64)) - .inv() - .unwrap(); + let factor = (FieldElement::::from( + u64::try_from(eval.len()).expect("as usize fits in u64 this should never fail"), + )) + .inv() + .unwrap(); eval_ordered.iter().map(|coef| coef * factor).collect() } diff --git a/crates/math/src/circle/twiddles.rs b/crates/math/src/circle/twiddles.rs index ef63c66f6..49307d7f3 100644 --- a/crates/math/src/circle/twiddles.rs +++ b/crates/math/src/circle/twiddles.rs @@ -1,8 +1,10 @@ extern crate alloc; +#[cfg(feature = "alloc")] use crate::{ circle::cosets::Coset, field::{element::FieldElement, fields::mersenne31::field::Mersenne31Field}, }; +#[cfg(feature = "alloc")] use alloc::vec::Vec; #[derive(PartialEq)] diff --git a/crates/math/src/fft/errors.rs b/crates/math/src/fft/errors.rs index 92a122238..84bfb3a58 100644 --- a/crates/math/src/fft/errors.rs +++ b/crates/math/src/fft/errors.rs @@ -63,6 +63,9 @@ impl From for FFTError { FieldError::InvZeroError => { panic!("Can't calculate inverse of zero during FFT"); } + FieldError::ConversionError => { + panic!("Can't convert usize to integer type during FFT"); + } FieldError::RootOfUnityError(order) => FFTError::RootOfUnityError(order), } } diff --git a/crates/math/src/field/element.rs b/crates/math/src/field/element.rs index 135908051..8d9da29a4 100644 --- a/crates/math/src/field/element.rs +++ b/crates/math/src/field/element.rs @@ -1,6 +1,9 @@ -use crate::errors::{ByteConversionError, CreationError}; +#[cfg(feature = "alloc")] +use crate::errors::ByteConversionError; +use crate::errors::CreationError; use crate::field::errors::FieldError; use crate::field::traits::IsField; +#[cfg(feature = "alloc")] use crate::traits::ByteConversion; use crate::unsigned_integer::element::UnsignedInteger; use crate::unsigned_integer::montgomery::MontgomeryAlgorithms; @@ -16,7 +19,9 @@ use core::iter::Sum; ))] use core::marker::PhantomData; use core::ops::{Add, AddAssign, Div, Mul, MulAssign, Neg, Sub}; +#[cfg(feature = "alloc")] use num_bigint::BigUint; +#[cfg(feature = "alloc")] use num_traits::Num; #[cfg(any( feature = "lambdaworks-serde-binary", @@ -836,7 +841,7 @@ mod tests { .map(|x| { FieldElement::::from(x) }) .sum::>() .value, - ((n - 1) as f64 / 2. * ((n - 1) as f64 + 1.)) as u64 % MODULUS + n * (n - 1) / 2 % MODULUS ); } diff --git a/crates/math/src/field/errors.rs b/crates/math/src/field/errors.rs index 7156e11c3..0849f2cc8 100644 --- a/crates/math/src/field/errors.rs +++ b/crates/math/src/field/errors.rs @@ -5,4 +5,6 @@ pub enum FieldError { RootOfUnityError(u64), /// Can't calculate inverse of zero InvZeroError, + /// usize conversion error + ConversionError, }