Skip to main content

encryption/hash/
mod.rs

1// Copyright (c) 2026 erik <erik@erik.xyz> — https://erik.xyz
2
3//! 哈希实现(对应 PHP 版 `Hash/`;SM3 位于 `guomi/`)。
4
5mod belt;
6mod blake2;
7mod blake3;
8mod sha256;
9mod sha3;
10mod streebog;
11
12pub use belt::BeltHashHasher;
13pub use blake2::{Blake2b512Hasher, Blake2s256Hasher};
14pub use blake3::Blake3Hasher;
15pub use sha3::{Sha3_256Hasher, Sha3_512Hasher};
16pub use sha256::Sha256Hasher;
17pub use streebog::{Streebog256Hasher, Streebog512Hasher};
18
19use sha2::Digest;
20
21use crate::contract::{Hasher, Identified};
22use crate::error::Result;
23
24/// 哈希器与底层摘要之间的桥:声明 `Core` 即由 blanket impl 获得 [`Hasher`]。
25///
26/// `Core` 走 RustCrypto `digest` **0.10** 代际:sha2 / sha3 / blake2 / streebog /
27/// belt-hash 转出的是同一个 `Digest` trait,故一个 blanket 覆盖全部(bound 写作
28/// `sha2::Digest` 只是取路径,本 crate 未直接依赖 `digest`)。SM3(`sm3` crate
29/// 属 digest 0.11 代际)与 BLAKE3(独立实现,不走 digest trait)不适用,
30/// 二者各自实现 [`Hasher`]。
31pub trait NamedDigest {
32    /// 提供摘要的底层实现。
33    type Core: Digest;
34}
35
36impl<D: NamedDigest + Identified + Send + Sync> Hasher for D {
37    fn digest(&self, data: &[u8]) -> Result<Vec<u8>> {
38        Ok(D::Core::digest(data).to_vec())
39    }
40}
41
42/// 生成无状态哈希器 ZST:固有 `IDENTIFIER` / `new()` 加 `Identified`
43/// (`Identified` 不能走 blanket——会与 `Box<T>` 的既有实现冲突);
44/// 摘要来源由各文件以 `NamedDigest`(SM3 / BLAKE3 则各自实现 `Hasher`)补上。
45macro_rules! hasher {
46    ($name:ident, $identifier:literal, $doc:literal $(,)?) => {
47        #[doc = $doc]
48        #[derive(Debug, Default, Clone, Copy)]
49        pub struct $name;
50
51        impl $name {
52            pub const IDENTIFIER: &'static str = $identifier;
53
54            pub fn new() -> Self {
55                Self
56            }
57        }
58
59        impl $crate::contract::Identified for $name {
60            fn identifier(&self) -> &str {
61                Self::IDENTIFIER
62            }
63        }
64    };
65}
66
67pub(crate) use hasher;