### SHA-512 x86/x86_64 AVX2 backend implementation Source: https://docs.rs/sha2/latest/src/sha2/sha512/x86_avx2.rs.html The complete source file for the SHA-512 x86/x86_64 AVX2 backend. It includes the `compress` function, AVX/AVX2 data loading helpers, and round processing functions. The code uses `#[target_feature(enable = "avx2")]` and requires x86 or x86_64 target architecture. ```rust //! SHA-512 `x86`/`x86_64` backend #![allow(clippy::many_single_char_names, unsafe_op_in_unsafe_fn)] #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] compile_error!("x86-avx2 backend can be used only on x86 and x86_64 target arches"); use core::mem::size_of; #[cfg(target_arch = "x86")] use core::arch::x86::*; #[cfg(target_arch = "x86_64")] use core::arch::x86_64::*; use crate::consts::K64; #[target_feature(enable = "avx2")] pub(super) unsafe fn compress(state: &mut [u64; 8], blocks: &[[u8; 128]]) { let mut start_block = 0; if blocks.len() & 0b1 != 0 { sha512_compress_x86_64_avx(state, &blocks[0]); start_block += 1; } let mut ms: MsgSchedule = [_mm_setzero_si128(); 8]; let mut t2: RoundStates = [_mm_setzero_si128(); 40]; let mut x = [_mm256_setzero_si256(); 8]; for i in (start_block..blocks.len()).step_by(2) { load_data_avx2(&mut x, &mut ms, &mut t2, blocks.as_ptr().add(i).cast()); // First block let mut current_state = *state; rounds_0_63_avx2(&mut current_state, &mut x, &mut ms, &mut t2); rounds_64_79(&mut current_state, &ms); accumulate_state(state, ¤t_state); // Second block current_state = *state; process_second_block(&mut current_state, &t2); accumulate_state(state, ¤t_state); } } #[inline(always)] unsafe fn sha512_compress_x86_64_avx(state: &mut [u64; 8], block: &[u8; 128]) { let mut ms = [_mm_setzero_si128(); 8]; let mut x = [_mm_setzero_si128(); 8]; // Reduced to single iteration let mut current_state = *state; load_data_avx(&mut x, &mut ms, block.as_ptr().cast()); rounds_0_63_avx(&mut current_state, &mut x, &mut ms); rounds_64_79(&mut current_state, &ms); accumulate_state(state, ¤t_state); } #[inline(always)] unsafe fn load_data_avx(x: &mut [__m128i; 8], ms: &mut MsgSchedule, data: *const __m128i) { #[allow(non_snake_case)] let MASK = _mm_setr_epi32(0x04050607, 0x00010203, 0x0c0d0e0f, 0x08090a0b); macro_rules! unrolled_iterations { ($($i:literal),*) => {$( x[$i] = _mm_loadu_si128(data.add($i).cast()); x[$i] = _mm_shuffle_epi8(x[$i], MASK); let y = _mm_add_epi64( x[$i], _mm_loadu_si128(K64.as_ptr().add(2 * $i).cast()), ); ms[$i] = y; )*}; } unrolled_iterations!(0, 1, 2, 3, 4, 5, 6, 7); } #[inline(always)] unsafe fn load_data_avx2( x: &mut [__m256i; 8], ms: &mut MsgSchedule, t2: &mut RoundStates, data: *const __m128i, ) { #[allow(non_snake_case)] let MASK = _mm256_set_epi64x( 0x0809_0A0B_0C0D_0E0F_i64, 0x0001_0203_0405_0607_i64, 0x0809_0A0B_0C0D_0E0F_i64, 0x0001_0203_0405_0607_i64, ); macro_rules! unrolled_iterations { ($($i:literal),*) => {$( x[$i] = _mm256_insertf128_si256(x[$i], _mm_loadu_si128(data.add(8 + $i).cast()), 1); x[$i] = _mm256_insertf128_si256(x[$i], _mm_loadu_si128(data.add($i).cast()), 0); x[$i] = _mm256_shuffle_epi8(x[$i], MASK); let t = _mm_loadu_si128(K64.as_ptr().add($i * 2).cast()); let y = _mm256_add_epi64(x[$i], _mm256_set_m128i(t, t)); ms[$i] = _mm256_extracti128_si256(y, 0); t2[$i] = _mm256_extracti128_si256(y, 1); )*}; } unrolled_iterations!(0, 1, 2, 3, 4, 5, 6, 7); } #[inline(always)] unsafe fn rounds_0_63_avx(current_state: &mut State, x: &mut [__m128i; 8], ms: &mut MsgSchedule) { let mut k64_idx: usize = SHA512_BLOCK_WORDS_NUM; for _ in 0..4 { for j in 0..8 { let k64 = _mm_loadu_si128(K64.as_ptr().add(k64_idx).cast()); let y = sha512_update_x_avx(x, k64); { let ms = cast_ms(ms); sha_round(current_state, ms[2 * j]); sha_round(current_state, ms[2 * j + 1]); } ms[j] = y; k64_idx += 2; } } } #[inline(always)] unsafe fn rounds_0_63_avx2( current_state: &mut State, x: &mut [__m256i; 8], ms: &mut MsgSchedule, t2: &mut RoundStates, ) { let mut k64x4_idx: usize = SHA512_BLOCK_WORDS_NUM; for i in 1..5 { for j in 0..8 { let t = _mm_loadu_si128(K64.as_ptr().add(k64x4_idx).cast()); let y = sha512_update_x_avx2(x, _mm256_set_m128i(t, t)); { let ms = cast_ms(ms); sha_round(current_state, ms[2 * j]); sha_round(current_state, ms[2 * j + 1]); } ms[j] = _mm256_extracti128_si256(y, 0); t2[j] = _mm256_extracti128_si256(y, 1); k64x4_idx += 2; } } } ``` -------------------------------- ### Backend selection and compress256 definition Source: https://docs.rs/sha2/latest/src/sha2/sha256.rs.html This snippet shows the entire sha256.rs module. It uses cfg_if! to select a SHA-256 backend (soft, riscv-zknh, x86-sha, aarch64-sha2, loongarch64, wasm32-simd128, or a runtime-detected fallback) and defines the public compress256 function that calls the selected compress function. The compress function operates on 32-bit state and 64-byte blocks for most backends, but the aarch64-sha2 backend uses 64-bit state and 128-byte blocks. The snippet includes compile_error! checks for missing target features. ```rust cfg_if::cfg_if! { if #[cfg(any(sha2_backend = "soft", sha2_256_backend = "soft"))] { mod soft; use soft::compress; } else if #[cfg(any(sha2_backend = "riscv-zknh", sha2_256_backend = "riscv-zknh"))] { mod riscv_zknh; #[cfg(not(all( target_feature = "zknh", any(target_feature = "zbb", target_feature = "zbkb") )))] compile_error!("riscv-zknh backend requires zknh and zbkb (or zbb) target features"); fn compress(state: &mut [u32; 8], blocks: &[[u8; 64]]) { // SAFETY: we checked above that the required target features are enabled unsafe { riscv_zknh::compress(state, blocks) } } } else if #[cfg(sha2_256_backend = "x86-sha")] { mod x86_sha; #[cfg(not(all( target_feature = "sha", target_feature = "sse2", target_feature = "ssse3", target_feature = "sse4.1", )))] compile_error!("x86-sha backend requires sha, sse2, ssse3, sse4.1 target features"); fn compress(state: &mut [u32; 8], blocks: &[[u8; 64]]) { // SAFETY: we checked above that the required target features are enabled unsafe { x86_sha::compress(state, blocks) } } } else if #[cfg(sha2_256_backend = "aarch64-sha2")] { mod aarch64_sha2; #[cfg(not(target_feature = "sha2"))] compile_error!("aarch64-sha2 backend requires sha2 target feature"); fn compress(state: &mut [u64; 8], blocks: &[[u8; 128]]) { // SAFETY: we checked above that the required target features are enabled unsafe { aarch64_sha2::compress(state, blocks) } } } else if #[cfg(target_arch = "loongarch64")] { mod loongarch64_asm; use loongarch64_asm::compress; } else if #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))] { mod wasm32_simd128; use wasm32_simd128::compress; } else { mod soft; cfg_if::cfg_if! { if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { mod x86_sha; cpufeatures::new!(shani_cpuid, "sha", "sse2", "ssse3", "sse4.1"); } else if #[cfg(target_arch = "aarch64")] { mod aarch64_sha2; cpufeatures::new!(sha2_hwcap, "sha2"); } } fn compress(state: &mut [u32; 8], blocks: &[[u8; 64]]) { cfg_if::cfg_if! { if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { if shani_cpuid::get() { // SAFETY: we checked that required target features are available return unsafe { x86_sha::compress(state, blocks) }; } } else if #[cfg(target_arch = "aarch64")] { if sha2_hwcap::get() { // SAFETY: we checked that `sha2` target feature is available return unsafe { aarch64_sha2::compress(state, blocks) }; } } } soft::compress(state, blocks); } } } /// Raw SHA-256 compression function. /// /// This is a low-level "hazmat" API which provides direct access to the core /// functionality of SHA-256. pub fn compress256(state: &mut [u32; 8], blocks: &[[u8; 64]]) { compress(state, blocks) } ``` -------------------------------- ### Incremental SHA-256 and SHA-512 hashing with update and finalize Source: https://docs.rs/sha2/latest/sha2/index.html Demonstrates incremental hashing with Sha256 and Sha512. Data is fed in multiple update calls before finalize, and the resulting digests are asserted against known values. ```rust use sha2::{Sha256, Sha512, Digest}; use hex_literal::hex; let mut hasher = Sha256::new(); hasher.update(b"hello "); hasher.update(b"world"); let hash256 = hasher.finalize(); assert_eq!(hash256, hex!("b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9")); let mut hasher = Sha512::new(); hasher.update(b"hello world"); let hash512 = hasher.finalize(); assert_eq!(hash512, hex!( "309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f" "989dd35bc670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f" )); ``` -------------------------------- ### Sha256VarCore::new Source: https://docs.rs/sha2/latest/sha2/block_api/struct.Sha256VarCore.html Initializes the hasher state for a given output size. Supports only 28 and 32 byte output sizes, corresponding to 224 and 256 bits respectively. ```APIDOC ## Sha256VarCore::new ### Description Initialize hasher state for a given output size. Supports only 28 and 32 byte output sizes, i.e. 224 and 256 bits respectively. ### Parameters - **output_size** (usize) - Required - Desired output size in bytes; must be 28 or 32. ### Return Value Result - Returns the initialized hasher or an InvalidOutputSize error if the output size is not supported. ``` -------------------------------- ### SHA-512 soft backend: cfg_if module selection and to_u64s conversion Source: https://docs.rs/sha2/latest/src/sha2/sha512/soft.rs.html Selects the SHA-512 compression implementation based on the `sha2_backend_soft` feature flag: uses the `compact` module when set to "compact", otherwise the `unroll` module. Also defines `to_u64s`, an inline helper that converts a 128-byte block into 16 big-endian `u64` words, panicking if the slice conversion fails. ```rust cfg_if::cfg_if! { if #[cfg(sha2_backend_soft = "compact")] { mod compact; pub(super) use compact::compress; } else { mod unroll; pub(super) use unroll::compress; } } #[inline(always)] fn to_u64s(block: &[u8; 128]) -> [u64; 16] { core::array::from_fn(|i| { let chunk = block[8 * i..][..8].try_into().unwrap(); u64::from_be_bytes(chunk) }) } ``` -------------------------------- ### Sha512VarCore AlgorithmName and Debug implementations Source: https://docs.rs/sha2/latest/src/sha2/block_api.rs.html Implements AlgorithmName to write the algorithm name "Sha512" and Debug to print a placeholder string. ```rust impl AlgorithmName for Sha512VarCore { #[inline] fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("Sha512") } } impl fmt::Debug for Sha512VarCore { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("Sha512VarCore { ... }") } } ``` -------------------------------- ### SHA-512 backend selection and raw compress512 function Source: https://docs.rs/sha2/latest/src/sha2/sha512.rs.html The first block selects the SHA-512 compression backend at compile time based on feature flags and target features, with compile_error! guards for missing required features. The second block exposes the raw SHA-512 compression function compress512 as a low-level "hazmat" API that delegates to the selected backend. ```rust cfg_if::cfg_if! { if #[cfg(any(sha2_backend = "soft", sha2_256_backend = "soft"))] { mod soft; use soft::compress; } else if #[cfg(any(sha2_backend = "riscv-zknh", sha2_256_backend = "riscv-zknh"))] { mod riscv_zknh; #[cfg(not(all( target_feature = "zknh", any(target_feature = "zbb", target_feature = "zbkb") )))] compile_error!("riscv-zknh backend requires zknh and zbkb (or zbb) target features"); fn compress(state: &mut [u64; 8], blocks: &[[u8; 128]]) { // SAFETY: we checked above that the required target features are enabled unsafe { riscv_zknh::compress(state, blocks) } } } else if #[cfg(sha2_512_backend = "x86-avx2")] { mod x86_avx2; #[cfg(not(target_feature = "avx2"))] compile_error!("x86-avx2 backend requires avx2 target feature"); fn compress(state: &mut [u32; 8], blocks: &[[u8; 64]]) { // SAFETY: we checked above that the required target features are enabled unsafe { x86_avx2::compress(state, blocks) } } } else if #[cfg(sha2_512_backend = "aarch64-sha3")] { mod aarch64_sha3; #[cfg(not(target_feature = "sha3"))] compile_error!("aarch64-sha3 backend requires sha3 target feature"); fn compress(state: &mut [u64; 8], blocks: &[[u8; 128]]) { // SAFETY: we checked above that the required target features are enabled unsafe { aarch64_sha3::compress(state, blocks) } } } else if #[cfg(target_arch = "loongarch64")] { mod loongarch64_asm; use loongarch64_asm::compress; } else if #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))] { mod wasm32_simd128; use wasm32_simd128::compress; } else { mod soft; cfg_if::cfg_if! { if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { mod x86_avx2; cpufeatures::new!(avx2_cpuid, "avx2"); } else if #[cfg(target_arch = "aarch64")] { mod aarch64_sha3; cpufeatures::new!(sha3_hwcap, "sha3"); } } fn compress(state: &mut [u64; 8], blocks: &[[u8; 128]]) { cfg_if::cfg_if! { if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { if avx2_cpuid::get() { // SAFETY: we checked that required target features are available return unsafe { x86_avx2::compress(state, blocks) }; } } else if #[cfg(target_arch = "aarch64")] { if sha3_hwcap::get() { // SAFETY: we checked that `sha3` target feature is available return unsafe { aarch64_sha3::compress(state, blocks) }; } } } soft::compress(state, blocks); } } } ``` ```rust /// Raw SHA-512 compression function. /// /// This is a low-level "hazmat" API which provides direct access to the core /// functionality of SHA-512. pub fn compress512(state: &mut [u64; 8], blocks: &[[u8; 128]]) { compress(state, blocks) } ``` -------------------------------- ### SHA-256 x86/x86_64 backend with Intel SHA intrinsics Source: https://docs.rs/sha2/latest/src/sha2/sha256/x86_sha.rs.html Implements the SHA-256 compression function for x86/x86_64 using Intel SHA extensions (sha, sse2, ssse3, sse4.1). The code defines a schedule helper and two macros (rounds4 and schedule_rounds4) to process 64-byte blocks, then stores the updated state. It requires the target architecture to be x86 or x86_64; otherwise it triggers a compile_error. The function is unsafe and uses unaligned loads and stores with __m128i pointers. ```rust 1//! SHA-256 `x86`/`x86_64` backend 2 3#![allow(clippy::many_single_char_names, unsafe_op_in_unsafe_fn)] 4 5#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] 6compile_error!("x86-sha backend can be used only on x86 and x86_64 target arches"); 7 8#[cfg(target_arch = "x86")] 9use core::arch::x86::*; 10#[cfg(target_arch = "x86_64")] 11use core::arch::x86_64::*; 12 13#[target_feature(enable = "sha,sse2,ssse3,sse4.1")] 14unsafe fn schedule(v0: __m128i, v1: __m128i, v2: __m128i, v3: __m128i) -> __m128i { 15 let t1 = _mm_sha256msg1_epu32(v0, v1); 16 let t2 = _mm_alignr_epi8(v3, v2, 4); 17 let t3 = _mm_add_epi32(t1, t2); 18 _mm_sha256msg2_epu32(t3, v3) 19} 20 21macro_rules! rounds4 { 22 ($abef:ident, $cdgh:ident, $rest:expr, $i:expr) => {{ 23 let k = crate::consts::K32X4[$i]; 24 let kv = _mm_set_epi32(k[0] as i32, k[1] as i32, k[2] as i32, k[3] as i32); 25 let t1 = _mm_add_epi32($rest, kv); 26 $cdgh = _mm_sha256rnds2_epu32($cdgh, $abef, t1); 27 let t2 = _mm_shuffle_epi32(t1, 0x0E); 28 $abef = _mm_sha256rnds2_epu32($abef, $cdgh, t2); 29 }}; 30} 31 32macro_rules! schedule_rounds4 { 33 ( 34 $abef:ident, $cdgh:ident, 35 $w0:expr, $w1:expr, $w2:expr, $w3:expr, $w4:expr, 36 $i: expr 37 ) => {{ 38 $w4 = schedule($w0, $w1, $w2, $w3); 39 rounds4!($abef, $cdgh, $w4, $i); 40 }}; 41} 42 43// we use unaligned loads with `__m128i` pointers 44#[allow(clippy::cast_ptr_alignment)] 45#[target_feature(enable = "sha,sse2,ssse3,sse4.1")] 46pub(super) unsafe fn compress(state: &mut [u32; 8], blocks: &[[u8; 64]]) { 47 #[allow(non_snake_case)] 48 let MASK: __m128i = _mm_set_epi64x( 49 0x0C0D_0E0F_0809_0A0Bu64 as i64, 50 0x0405_0607_0001_0203u64 as i64, 51 ); 52 53 let state_ptr: *const __m128i = state.as_ptr().cast(); 54 let dcba = _mm_loadu_si128(state_ptr.add(0)); 55 let hgfe = _mm_loadu_si128(state_ptr.add(1)); 56 57 let cdab = _mm_shuffle_epi32(dcba, 0xB1); 58 let efgh = _mm_shuffle_epi32(hgfe, 0x1B); 59 let mut abef = _mm_alignr_epi8(cdab, efgh, 8); 60 let mut cdgh = _mm_blend_epi16(efgh, cdab, 0xF0); 61 62 for block in blocks { 63 let abef_save = abef; 64 let cdgh_save = cdgh; 65 66 let block_ptr: *const __m128i = block.as_ptr().cast(); 67 let mut w0 = _mm_shuffle_epi8(_mm_loadu_si128(block_ptr.add(0)), MASK); 68 let mut w1 = _mm_shuffle_epi8(_mm_loadu_si128(block_ptr.add(1)), MASK); 69 let mut w2 = _mm_shuffle_epi8(_mm_loadu_si128(block_ptr.add(2)), MASK); 70 let mut w3 = _mm_shuffle_epi8(_mm_loadu_si128(block_ptr.add(3)), MASK); 71 let mut w4; 72 73 rounds4!(abef, cdgh, w0, 0); 74 rounds4!(abef, cdgh, w1, 1); 75 rounds4!(abef, cdgh, w2, 2); 76 rounds4!(abef, cdgh, w3, 3); 77 schedule_rounds4!(abef, cdgh, w0, w1, w2, w3, w4, 4); 78 schedule_rounds4!(abef, cdgh, w1, w2, w3, w4, w0, 5); 79 schedule_rounds4!(abef, cdgh, w2, w3, w4, w0, w1, 6); 80 schedule_rounds4!(abef, cdgh, w3, w4, w0, w1, w2, 7); 81 schedule_rounds4!(abef, cdgh, w4, w0, w1, w2, w3, 8); 82 schedule_rounds4!(abef, cdgh, w0, w1, w2, w3, w4, 9); 83 schedule_rounds4!(abef, cdgh, w1, w2, w3, w4, w0, 10); 84 schedule_rounds4!(abef, cdgh, w2, w3, w4, w0, w1, 11); 85 schedule_rounds4!(abef, cdgh, w3, w4, w0, w1, w2, 12); 86 schedule_rounds4!(abef, cdgh, w4, w0, w1, w2, w3, 13); 87 schedule_rounds4!(abef, cdgh, w0, w1, w2, w3, w4, 14); 88 schedule_rounds4!(abef, cdgh, w1, w2, w3, w4, w0, 15); 89 90 abef = _mm_add_epi32(abef, abef_save); 91 cdgh = _mm_add_epi32(cdgh, cdgh_save); 92 } 93 94 let feba = _mm_shuffle_epi32(abef, 0x1B); 95 let dchg = _mm_shuffle_epi32(cdgh, 0xB1); 96 let dcba = _mm_blend_epi16(feba, dchg, 0xF0); 97 let hgef = _mm_alignr_epi8(dchg, feba, 8); 98 99 let state_ptr_mut: *mut __m128i = state.as_mut_ptr().cast(); 100 _mm_storeu_si128(state_ptr_mut.add(0), dcba); 101 _mm_storeu_si128(state_ptr_mut.add(1), hgef); 102} ``` -------------------------------- ### Sha512VarCore Drop and ZeroizeOnDrop implementations Source: https://docs.rs/sha2/latest/src/sha2/block_api.rs.html Implements Drop to zeroize state and block_len when the zeroize feature is enabled, and implements ZeroizeOnDrop for automatic zeroization on drop. ```rust impl Drop for Sha512VarCore { fn drop(&mut self) { #[cfg(feature = "zeroize")] { use digest::zeroize::Zeroize; self.state.zeroize(); self.block_len.zeroize(); } } } #[cfg(feature = "zeroize")] impl digest::zeroize::ZeroizeOnDrop for Sha512VarCore {} ``` -------------------------------- ### SHA-256 soft backend: cfg_if module selection and to_u32s conversion Source: https://docs.rs/sha2/latest/src/sha2/sha256/soft.rs.html The first block selects the SHA-256 compression implementation based on the `sha2_backend_soft` configuration flag: when set to "compact", it uses the `compact` module; otherwise, it uses the `unroll` module. The second block converts a 64-byte input block into an array of 16 `u32` values using big-endian byte order, which is a common step in SHA-256 processing. ```rust cfg_if::cfg_if! { if #[cfg(sha2_backend_soft = "compact")] { mod compact; pub(super) use compact::compress; } else { mod unroll; pub(super) use unroll::compress; } } ``` ```rust fn to_u32s(block: &[u8; 64]) -> [u32; 16] { core::array::from_fn(|i| { let chunk = block[4 * i..][..4].try_into().unwrap(); u32::from_be_bytes(chunk) }) } ``` -------------------------------- ### sha2 block_api.rs: Sha256VarCore and Sha512VarCore implementations Source: https://docs.rs/sha2/latest/src/sha2/block_api.rs.html Complete implementation of the block_api module for the sha2 crate, defining Sha256VarCore and Sha512VarCore with variable output size support, serialization, and zeroization. ```rust use crate::consts; use core::fmt; use digest::{ HashMarker, InvalidOutputSize, Output, array::Array, block_api::{ AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, Eager, OutputSizeUser, TruncSide, UpdateCore, VariableOutputCore, }, common::hazmat::{DeserializeStateError, SerializableState, SerializedState}, typenum::{U32, U40, U64, U80, U128, Unsigned}, }; pub use crate::{sha256::compress256, sha512::compress512}; /// Core block-level SHA-256 hasher with variable output size. /// /// Supports initialization only for 28 and 32 byte output sizes, /// i.e. 224 and 256 bits respectively. #[derive(Clone)] pub struct Sha256VarCore { state: consts::State256, block_len: u64, } impl HashMarker for Sha256VarCore {} impl BlockSizeUser for Sha256VarCore { type BlockSize = U64; } impl BufferKindUser for Sha256VarCore { type BufferKind = Eager; } impl UpdateCore for Sha256VarCore { #[inline] fn update_blocks(&mut self, blocks: &[Block]) { self.block_len += blocks.len() as u64; let blocks = Array::cast_slice_to_core(blocks); compress256(&mut self.state, blocks); } } impl OutputSizeUser for Sha256VarCore { type OutputSize = U32; } impl VariableOutputCore for Sha256VarCore { const TRUNC_SIDE: TruncSide = TruncSide::Left; #[inline] fn new(output_size: usize) -> Result { let state = match output_size { 28 => consts::H256_224, 32 => consts::H256_256, _ => return Err(InvalidOutputSize), }; let block_len = 0; Ok(Self { state, block_len }) } #[inline] fn finalize_variable_core(&mut self, buffer: &mut Buffer, out: &mut Output) { let bs = Self::BlockSize::U64; let bit_len = 8 * (buffer.get_pos() as u64 + bs * self.block_len); buffer.len64_padding_be(bit_len, |b| compress256(&mut self.state, &[b.0])); for (chunk, v) in out.chunks_exact_mut(4).zip(self.state.iter()) { chunk.copy_from_slice(&v.to_be_bytes()); } } } impl AlgorithmName for Sha256VarCore { #[inline] fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("Sha256") } } impl fmt::Debug for Sha256VarCore { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("Sha256VarCore { ... }") } } impl Drop for Sha256VarCore { fn drop(&mut self) { #[cfg(feature = "zeroize")] { use digest::zeroize::Zeroize; self.state.zeroize(); self.block_len.zeroize(); } } } #[cfg(feature = "zeroize")] impl digest::zeroize::ZeroizeOnDrop for Sha256VarCore {} impl SerializableState for Sha256VarCore { type SerializedStateSize = U40; fn serialize(&self) -> SerializedState { let mut serialized_state = SerializedState::::default(); for (val, chunk) in self.state.iter().zip(serialized_state.chunks_exact_mut(4)) { chunk.copy_from_slice(&val.to_le_bytes()); } serialized_state[32..].copy_from_slice(&self.block_len.to_le_bytes()); serialized_state } fn deserialize( serialized_state: &SerializedState, ) -> Result { let (serialized_state, serialized_block_len) = serialized_state.split::(); let mut state = consts::State256::default(); for (val, chunk) in state.iter_mut().zip(serialized_state.chunks_exact(4)) { *val = u32::from_le_bytes(chunk.try_into().unwrap()); } let block_len = u64::from_le_bytes(*serialized_block_len.as_ref()); Ok(Self { state, block_len }) } } /// Core block-level SHA-512 hasher with variable output size. /// /// Supports initialization only for 28, 32, 48, and 64 byte output sizes, /// i.e. 224, 256, 384, and 512 bits respectively. #[derive(Clone)] pub struct Sha512VarCore { state: consts::State512, block_len: u128, } impl HashMarker for Sha512VarCore {} impl BlockSizeUser for Sha512VarCore { type BlockSize = U128; } impl BufferKindUser for Sha512VarCore { type BufferKind = Eager; } impl UpdateCore for Sha512VarCore { #[inline] fn update_blocks(&mut self, blocks: &[Block]) { self.block_len += blocks.len() as u128; let blocks = Array::cast_slice_to_core(blocks); compress512(&mut self.state, blocks); } } impl OutputSizeUser for Sha512VarCore { type OutputSize = U128; } impl VariableOutputCore for Sha512VarCore { const TRUNC_SIDE: TruncSide = TruncSide::Left; #[inline] fn new(output_size: usize) -> Result { let state = match output_size { 28 => consts::H512_224, 32 => consts::H512_256, 48 => consts::H512_384, 64 => consts::H512_512, _ => return Err(InvalidOutputSize), }; let block_len = 0; Ok(Self { state, block_len }) } #[inline] fn finalize_variable_core(&mut self, buffer: &mut Buffer, out: &mut Output) { let bs = Self::BlockSize::U128; let bit_len = 8 * (buffer.get_pos() as u128 + bs * self.block_len); buffer.len128_padding_be(bit_len, |b| compress512(&mut self.state, &[b.0])); for (chunk, v) in out.chunks_exact_mut(8).zip(self.state.iter()) { chunk.copy_from_slice(&v.to_be_bytes()); } } } impl AlgorithmName for Sha512VarCore { #[inline] fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("Sha512") } } impl fmt::Debug for Sha512VarCore { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("Sha512VarCore { ... }") } } impl Drop for Sha512VarCore { fn drop(&mut self) { #[cfg(feature = "zeroize")] { use digest::zeroize::Zeroize; self.state.zeroize(); self.block_len.zeroize(); } } } #[cfg(feature = "zeroize")] impl digest::zeroize::ZeroizeOnDrop for Sha512VarCore {} impl SerializableState for Sha512VarCore { type SerializedStateSize = U80; fn serialize(&self) -> SerializedState { let mut serialized_state = SerializedState::::default(); for (val, chunk) in self.state.iter().zip(serialized_state.chunks_exact_mut(8)) { chunk.copy_from_slice(&val.to_le_bytes()); } serialized_state[64..].copy_from_slice(&self.block_len.to_le_bytes()); serialized_state } fn deserialize( serialized_state: &SerializedState, ) -> Result { let (serialized_state, serialized_block_len) = serialized_state.split::(); let mut state = consts::State512::default(); for (val, chunk) in state.iter_mut().zip(serialized_state.chunks_exact(8)) { *val = u64::from_le_bytes(chunk.try_into().unwrap()); } let block_len = u128::from_le_bytes(*serialized_block_len.as_ref()); Ok(Self { state, block_len }) } } ``` -------------------------------- ### compress256 Source: https://docs.rs/sha2/latest/sha2/block_api/fn.compress256.html Documentation for the compress256 function, a low-level SHA-256 compression function. ```APIDOC ## compress256 ### Description Raw SHA-256 compression function. This is a low-level "hazmat" API which provides direct access to the core functionality of SHA-256. ### Function Signature ```rust pub fn compress256(state: &mut [u32; 8], blocks: &[[u8; 64]]) ``` ### Parameters - **state** (`&mut [u32; 8]`) - Required - The state to be updated by the compression function. - **blocks** (`&[[u8; 64]]`) - Required - The blocks to compress. ### Return Value None (unit type). ```