a4ca734d0d
主要变更: - 新增 sm2/、sm3/、sm4/ 独立 crate,实现 RustCrypto traits - sm2:实现 signature、elliptic-curve traits - sm3:实现 digest、crypto-common traits - sm4:实现 cipher、aead traits - 新增 fuzz/ 模糊测试目标 - 新增 tests/sm2_proptest.rs 属性测试 - 重构 src/sm4/ 使用 RustCrypto AEAD traits - 更新 CI 工作流支持多 crate 测试 - 更新 .gitignore 忽略 fuzz/target/
99 lines
3.0 KiB
Rust
99 lines
3.0 KiB
Rust
//! SM3 block-level core (low-level internal type).
|
||
//!
|
||
//! Users should use [`Sm3`] from the crate root instead.
|
||
|
||
use core::fmt;
|
||
use digest::{
|
||
HashMarker,
|
||
block_api::{
|
||
AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser,
|
||
Eager, FixedOutputCore, OutputSizeUser, UpdateCore,
|
||
},
|
||
typenum::{U32, U64, Unsigned},
|
||
};
|
||
|
||
use crate::compress;
|
||
|
||
// ── Sm3Core ───────────────────────────────────────────────────────────────────
|
||
|
||
/// Low-level SM3 block-processing core.
|
||
///
|
||
/// Implements the `digest::block_api` low-level traits so that the
|
||
/// [`digest::buffer_fixed!`] macro can wrap it into a fully-featured [`Sm3`].
|
||
#[derive(Clone)]
|
||
pub struct Sm3Core {
|
||
state: [u32; 8],
|
||
/// Number of **complete** 64-byte blocks already compressed.
|
||
block_len: u64,
|
||
}
|
||
|
||
impl HashMarker for Sm3Core {}
|
||
|
||
impl BlockSizeUser for Sm3Core {
|
||
/// SM3 processes 512-bit (64-byte) blocks.
|
||
type BlockSize = U64;
|
||
}
|
||
|
||
impl BufferKindUser for Sm3Core {
|
||
/// Eager: compress each full block immediately.
|
||
type BufferKind = Eager;
|
||
}
|
||
|
||
impl OutputSizeUser for Sm3Core {
|
||
/// SM3 produces a 256-bit (32-byte) digest.
|
||
type OutputSize = U32;
|
||
}
|
||
|
||
impl Default for Sm3Core {
|
||
fn default() -> Self {
|
||
Self { state: compress::IV, block_len: 0 }
|
||
}
|
||
}
|
||
|
||
impl digest::Reset for Sm3Core {
|
||
fn reset(&mut self) {
|
||
*self = Self::default();
|
||
}
|
||
}
|
||
|
||
impl UpdateCore for Sm3Core {
|
||
#[inline]
|
||
fn update_blocks(&mut self, blocks: &[Block<Self>]) {
|
||
// Reason: only complete blocks are counted here; the partial tail is
|
||
// held by the surrounding BlockBuffer and counted in finalize.
|
||
self.block_len += blocks.len() as u64;
|
||
for block in blocks {
|
||
// Reason: hybrid_array::Array<u8, U64> implements Deref<Target=[u8]>,
|
||
// so we get a &[u8] slice then cast to &[u8; 64] via try_into.
|
||
let b: &[u8; 64] = (&**block).try_into().unwrap();
|
||
compress::compress(&mut self.state, b);
|
||
}
|
||
}
|
||
}
|
||
|
||
impl FixedOutputCore for Sm3Core {
|
||
#[inline]
|
||
fn finalize_fixed_core(&mut self, buffer: &mut Buffer<Self>, out: &mut digest::Output<Self>) {
|
||
// Total bit length = (complete blocks × 64 + partial tail) × 8
|
||
let bs = U64::U64;
|
||
let bit_len = 8 * (buffer.get_pos() as u64 + bs * self.block_len);
|
||
|
||
// GB/T 32905 §5.3.1 padding: 0x80, zeros, 64-bit big-endian bit count
|
||
buffer.len64_padding_be(bit_len, |block| {
|
||
let b: &[u8; 64] = (&**block).try_into().unwrap();
|
||
compress::compress(&mut self.state, b);
|
||
});
|
||
|
||
// Serialize state as big-endian u32 words
|
||
for (chunk, &word) in out.chunks_exact_mut(4).zip(self.state.iter()) {
|
||
chunk.copy_from_slice(&word.to_be_bytes());
|
||
}
|
||
}
|
||
}
|
||
|
||
impl AlgorithmName for Sm3Core {
|
||
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||
f.write_str("Sm3")
|
||
}
|
||
}
|