diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index 6b2d7f8..62adf08 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -17,7 +17,7 @@ jobs: - uses: RustCrypto/actions/cargo-cache@master - uses: dtolnay/rust-toolchain@master with: - toolchain: 1.85.0 + toolchain: 1.93.0 components: clippy - run: cargo clippy --all -- -D warnings diff --git a/Cargo.toml b/Cargo.toml index ee29985..b56b844 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,46 @@ [workspace] -resolver = "2" +resolver = "3" members = [ "ascon", "bash-f", "keccak", ] + +[workspace.lints.clippy] +borrow_as_ptr = "warn" +cast_lossless = "warn" +cast_possible_truncation = "warn" +cast_possible_wrap = "warn" +cast_precision_loss = "warn" +cast_sign_loss = "warn" +checked_conversions = "warn" +from_iter_instead_of_collect = "warn" +implicit_saturating_sub = "warn" +manual_assert = "warn" +map_unwrap_or = "warn" +missing_errors_doc = "warn" +missing_panics_doc = "warn" +mod_module_files = "warn" +must_use_candidate = "warn" +needless_range_loop = "allow" +ptr_as_ptr = "warn" +redundant_closure_for_method_calls = "warn" +ref_as_ptr = "warn" +return_self_not_must_use = "warn" +semicolon_if_nothing_returned = "warn" +trivially_copy_pass_by_ref = "warn" +std_instead_of_alloc = "warn" +std_instead_of_core = "warn" +undocumented_unsafe_blocks = "warn" +unnecessary_safety_comment = "warn" +unwrap_in_result = "warn" +unwrap_used = "warn" + +[workspace.lints.rust] +missing_copy_implementations = "warn" +missing_debug_implementations = "warn" +missing_docs = "warn" +trivial_casts = "warn" +trivial_numeric_casts = "warn" +unused_lifetimes = "warn" +unused_qualifications = "warn" diff --git a/ascon/Cargo.toml b/ascon/Cargo.toml index 66643a3..6f6017e 100644 --- a/ascon/Cargo.toml +++ b/ascon/Cargo.toml @@ -22,5 +22,8 @@ zeroize = { version = "1.6", default-features = false, optional = true } [features] no_unroll = [] # Do not unroll loops for binary size reduction +[lints] +workspace = true + [package.metadata.docs.rs] rustdoc-args = ["--cfg", "docsrs"] diff --git a/ascon/LICENSE-MIT b/ascon/LICENSE-MIT index e4ea684..ae3c392 100644 --- a/ascon/LICENSE-MIT +++ b/ascon/LICENSE-MIT @@ -1,4 +1,4 @@ -Copyright (c) 2016-2023 quininer kel, RustCrypto Developers +Copyright (c) 2016-2026 Sebastian Ramacher, RustCrypto Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/ascon/README.md b/ascon/README.md index 99af549..6a4d1a6 100644 --- a/ascon/README.md +++ b/ascon/README.md @@ -18,8 +18,8 @@ easy to implement. Ascon is a family of lightweight algorithms built on a core permutation algorithm. These algorithms include: -- [x] [`ascon-aead`]: Authenticated Encryption with Associated Data -- [x] [`ascon-hash`]: Hash functions and extendible-output functions (XOF) +- [x] [`ascon-aead128`]: Authenticated Encryption with Associated Data +- [x] [`ascon-hash256`]: Hash functions and extendible-output functions (XOF) - [ ] Pseudo-random functions (PRF) and message authentication codes (MAC) Ascon has been selected as [new standard for lightweight cryptography] in the @@ -64,8 +64,8 @@ dual licensed as above, without any additional terms or conditions. [//]: # (links) -[`ascon-aead`]: https://github.com/RustCrypto/AEADs/tree/master/ascon-aead -[`ascon-hash`]: https://github.com/RustCrypto/hashes/tree/master/ascon-hash +[`ascon-aead128`]: https://docs.rs/ascon-aead128 +[`ascon-hash256`]: https://docs.rs/ascon-hash256 [RustCrypto]: https://github.com/rustcrypto [Ascon]: https://ascon.iaik.tugraz.at/ [New standard for lightweight cryptography]: https://www.nist.gov/news-events/news/2023/02/nist-selects-lightweight-cryptography-algorithms-protect-small-devices diff --git a/ascon/src/lib.rs b/ascon/src/lib.rs index faed020..1803982 100644 --- a/ascon/src/lib.rs +++ b/ascon/src/lib.rs @@ -1,22 +1,18 @@ -// Copyright 2021-2022 Sebastian Ramacher -// SPDX-License-Identifier: Apache-2.0 OR MIT - #![no_std] -#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(docsrs, feature(doc_cfg))] #![doc = include_str!("../README.md")] #![doc( html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" )] #![forbid(unsafe_code)] -#![warn(missing_docs)] -use core::mem::size_of; #[cfg(feature = "zeroize")] use zeroize::{Zeroize, ZeroizeOnDrop}; /// Produce mask for padding. #[inline(always)] +#[must_use] pub const fn pad(n: usize) -> u64 { 0x80_u64 << (56 - 8 * n) } @@ -31,6 +27,7 @@ const fn round_constant(round: u64) -> u64 { /// /// The permutation operates on a state of 320 bits represented as 5 64 bit words. #[derive(Clone, Debug, Default)] +#[allow(missing_copy_implementations)] pub struct State { x: [u64; 5], } @@ -68,6 +65,7 @@ const fn round(x: [u64; 5], c: u64) -> [u64; 5] { impl State { /// Instantiate new state from the given values. + #[must_use] pub fn new(x0: u64, x1: u64, x2: u64, x3: u64, x4: u64) -> Self { State { x: [x0, x1, x2, x3, x4], @@ -181,6 +179,7 @@ impl State { } /// Convert state to bytes. + #[must_use] pub fn as_bytes(&self) -> [u8; 40] { let mut bytes = [0u8; size_of::() * 5]; for (dst, src) in bytes.chunks_exact_mut(size_of::()).zip(self.x) { @@ -227,15 +226,16 @@ impl TryFrom<&[u8]> for State { type Error = (); fn try_from(value: &[u8]) -> Result { - if value.len() != core::mem::size_of::() * 5 { + if value.len() != size_of::() * 5 { return Err(()); } let mut state = Self::default(); - for (src, dst) in value - .chunks_exact(core::mem::size_of::()) - .zip(state.x.iter_mut()) - { + + // TODO(tarcieri): use `[T]::as_chunks` when MSRV 1.88 + #[allow(clippy::unwrap_in_result, reason = "MSRV")] + #[allow(clippy::unwrap_used, reason = "MSRV")] + for (src, dst) in value.chunks_exact(size_of::()).zip(state.x.iter_mut()) { *dst = u64::from_be_bytes(src.try_into().unwrap()); } Ok(state) @@ -245,10 +245,10 @@ impl TryFrom<&[u8]> for State { impl From<&[u8; size_of::() * 5]> for State { fn from(value: &[u8; size_of::() * 5]) -> Self { let mut state = Self::default(); - for (src, dst) in value - .chunks_exact(core::mem::size_of::()) - .zip(state.x.iter_mut()) - { + + // TODO(tarcieri): use `[T]::as_chunks` when MSRV 1.88 + #[allow(clippy::unwrap_used, reason = "MSRV")] + for (src, dst) in value.chunks_exact(size_of::()).zip(state.x.iter_mut()) { *dst = u64::from_be_bytes(src.try_into().unwrap()); } state diff --git a/bash-f/Cargo.toml b/bash-f/Cargo.toml index 99ba9f9..7baffdd 100644 --- a/bash-f/Cargo.toml +++ b/bash-f/Cargo.toml @@ -12,3 +12,6 @@ categories = ["cryptography", "no-std"] readme = "README.md" edition = "2024" rust-version = "1.85" + +[lints] +workspace = true diff --git a/bash-f/README.md b/bash-f/README.md index 427d249..a5fbabb 100644 --- a/bash-f/README.md +++ b/bash-f/README.md @@ -1,4 +1,4 @@ -# RustCrypto: bash-f +# [RustCrypto]: bash-f [![crate][crate-image]][crate-link] [![Docs][docs-image]][docs-link] @@ -39,3 +39,7 @@ dual licensed as above, without any additional terms or conditions. [rustc-image]: https://img.shields.io/badge/rustc-1.85+-blue.svg [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/369879-sponges + +[//]: # (links) + +[RustCrypto]: https://github.com/RustCrypto diff --git a/bash-f/benches/mod.rs b/bash-f/benches/mod.rs index 542c7ac..daa486e 100644 --- a/bash-f/benches/mod.rs +++ b/bash-f/benches/mod.rs @@ -1,3 +1,5 @@ +//! bash-f benchmarks + #![feature(test)] extern crate test; diff --git a/bash-f/tests/bash.rs b/bash-f/tests/bash.rs index 2df9772..37fba61 100644 --- a/bash-f/tests/bash.rs +++ b/bash-f/tests/bash.rs @@ -1,3 +1,5 @@ +//! bash-f tests + /// Test vector from Table A.2 of STB 34.101.77-2020. #[test] fn test_bash_f_table_a2() { @@ -58,8 +60,8 @@ fn test_bash_f_table_a2() { 0x7CED8E3F8B6E058E, ]; - let mut state = input.map(|x| x.swap_bytes()); - let expected = expected.map(|x| x.swap_bytes()); + let mut state = input.map(u64::swap_bytes); + let expected = expected.map(u64::swap_bytes); bash_f::bash_f(&mut state); diff --git a/keccak/Cargo.toml b/keccak/Cargo.toml index abc6d8a..48383fc 100644 --- a/keccak/Cargo.toml +++ b/keccak/Cargo.toml @@ -23,3 +23,6 @@ simd = [] # Use core::simd (nightly-only) [target.'cfg(target_arch = "aarch64")'.dependencies] cpufeatures = "0.3" + +[lints] +workspace = true diff --git a/keccak/README.md b/keccak/README.md index 1f3fb9a..0eb6020 100644 --- a/keccak/README.md +++ b/keccak/README.md @@ -1,4 +1,4 @@ -# RustCrypto: Keccak Sponge Function +# [RustCrypto]: Keccak Sponge Function [![crate][crate-image]][crate-link] [![Docs][docs-image]][docs-link] @@ -7,7 +7,7 @@ ![Rust Version][rustc-image] [![Project Chat][chat-image]][chat-link] -Pure Rust implementation of the [Keccak Sponge Function][1] including the keccak-f +Pure Rust implementation of the [Keccak Sponge Function][keccak] including the keccak-f and keccak-p variants. [Documentation][docs-link] @@ -60,7 +60,8 @@ dual licensed as above, without any additional terms or conditions. [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/369879-sponges -[//]: # (general links) +[//]: # (links) -[1]: https://keccak.team/keccak.html +[RustCrypto]: https://github.com/RustCrypto +[keccak]: https://keccak.team/keccak.html [`sha3`]: https://github.com/RustCrypto/hashes/tree/master/sha3 diff --git a/keccak/benches/mod.rs b/keccak/benches/mod.rs index 80352a8..34dd3d3 100644 --- a/keccak/benches/mod.rs +++ b/keccak/benches/mod.rs @@ -1,3 +1,5 @@ +//! keccak benchmarks + #![feature(test)] #![cfg_attr(feature = "simd", feature(portable_simd))] diff --git a/keccak/src/armv8.rs b/keccak/src/armv8.rs index e9dcfd3..427c916 100644 --- a/keccak/src/armv8.rs +++ b/keccak/src/armv8.rs @@ -1,10 +1,21 @@ -/// Keccak-p1600 on ARMv8.4-A with FEAT_SHA3. +/// Keccak-p1600 on ARMv8.4-A with `FEAT_SHA3`. /// /// See p. K12.2.2 p. 11,749 of the ARM Reference manual. /// Adapted from the Keccak-f1600 implementation in the XKCP/K12. /// see #[target_feature(enable = "sha3")] pub unsafe fn p1600_armv8_sha3_asm(state: &mut [u64; 25], round_count: usize) { + assert!( + matches!(round_count, 1..=24), + "invalid round count (must be 1-24): {}", + round_count + ); + + // SAFETY: + // - caller is responsible for ensuring that the target CPU is at least ARMv8.4-A with + // `FEAT_SHA3` using runtime CPU feature detection + // - `round_count` is ensured to be in the range `1..=24` above + // - `state` is valid, aligned, and mutably borrowed as a Rust reference above unsafe { core::arch::asm!(" // Read state @@ -123,6 +134,7 @@ pub unsafe fn p1600_armv8_sha3_asm(state: &mut [u64; 25], round_count: usize) { } #[cfg(all(test, target_feature = "sha3"))] +#[allow(clippy::undocumented_unsafe_blocks)] mod tests { use super::*; diff --git a/keccak/src/lib.rs b/keccak/src/lib.rs index 14cbb3d..f80669f 100644 --- a/keccak/src/lib.rs +++ b/keccak/src/lib.rs @@ -1,10 +1,16 @@ -//! Keccak [sponge function](https://en.wikipedia.org/wiki/Sponge_function). +#![no_std] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(feature = "simd", feature(portable_simd))] +#![doc = include_str!("../README.md")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" +)] +#![allow(non_upper_case_globals)] + +//! ## Usage //! -//! If you are looking for SHA-3 hash functions take a look at [`sha3`][1] and -//! [`tiny-keccak`][2] crates. -//! -//! To disable loop unrolling (e.g. for constraint targets) use `no_unroll` -//! feature. +//! To disable loop unrolling (e.g. for constrained targets) use `no_unroll` feature. //! //! ``` //! // Test vectors are from KeccakCodePackage @@ -36,23 +42,6 @@ //! [1]: https://docs.rs/sha3 //! [2]: https://docs.rs/tiny-keccak -#![no_std] -#![cfg_attr(docsrs, feature(doc_cfg))] -#![cfg_attr(feature = "simd", feature(portable_simd))] -#![doc( - html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", - html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" -)] -#![allow(non_upper_case_globals)] -#![warn( - clippy::mod_module_files, - clippy::unwrap_used, - missing_docs, - rust_2018_idioms, - unused_lifetimes, - unused_qualifications -)] - use core::{ fmt::Debug, mem::size_of, @@ -126,6 +115,7 @@ pub trait LaneSize: fn truncate_rc(rc: u64) -> Self; /// Rotate left function. + #[must_use] fn rotate_left(self, n: u32) -> Self; } @@ -179,20 +169,22 @@ impl_keccak!(p800, f800, u32); #[cfg(not(all(target_arch = "aarch64", feature = "asm")))] impl_keccak!(p1600, f1600, u64); -/// Keccak-p[1600, rc] permutation. +/// `Keccak-p[1600, rc]` permutation. #[cfg(all(target_arch = "aarch64", feature = "asm"))] pub fn p1600(state: &mut [u64; PLEN], round_count: usize) { if armv8_sha3_intrinsics::get() { + // SAFETY: we just performed runtime CPU feature detection above unsafe { armv8::p1600_armv8_sha3_asm(state, round_count) } } else { keccak_p(state, round_count); } } -/// Keccak-f[1600] permutation. +/// `Keccak-f[1600]` permutation. #[cfg(all(target_arch = "aarch64", feature = "asm"))] pub fn f1600(state: &mut [u64; PLEN]) { if armv8_sha3_intrinsics::get() { + // SAFETY: we just performed runtime CPU feature detection above unsafe { armv8::p1600_armv8_sha3_asm(state, 24) } } else { keccak_p(state, u64::KECCAK_F_ROUND_COUNT); @@ -230,12 +222,16 @@ pub mod simd { impl_keccak!(p1600x8, f1600x8, u64x8); } +/// Generic Keccak-p sponge function. +/// +/// # Panics +/// If the round count is greater than `L::KECCAK_F_ROUND_COUNT`. #[allow(unused_assignments)] -/// Generic Keccak-p sponge function pub fn keccak_p(state: &mut [L; PLEN], round_count: usize) { - if round_count > L::KECCAK_F_ROUND_COUNT { - panic!("A round_count greater than KECCAK_F_ROUND_COUNT is not supported!"); - } + assert!( + round_count <= L::KECCAK_F_ROUND_COUNT, + "A round_count greater than KECCAK_F_ROUND_COUNT is not supported!" + ); // https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf#page=25 // "the rounds of KECCAK-p[b, nr] match the last rounds of KECCAK-f[b]"