Skip to main content

aptos_sdk/crypto/
hash.rs

1//! Hash functions for the Aptos SDK.
2//!
3//! Provides SHA2-256 and SHA3-256 hash functions used throughout Aptos.
4
5use sha2::Digest as Sha2Digest;
6
7/// Available hash functions.
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum HashFunction {
10    /// SHA2-256 (used for Secp256k1 ECDSA)
11    Sha2_256,
12    /// SHA3-256 (used for Ed25519 and authentication keys)
13    Sha3_256,
14}
15
16/// Computes the SHA2-256 hash of the input.
17///
18/// This is used for Secp256k1 ECDSA message hashing.
19///
20/// # Example
21///
22/// ```rust
23/// use aptos_sdk::crypto::sha2_256;
24///
25/// let hash = sha2_256(b"hello world");
26/// assert_eq!(hash.len(), 32);
27/// ```
28pub fn sha2_256(data: &[u8]) -> [u8; 32] {
29    let mut hasher = sha2::Sha256::new();
30    hasher.update(data);
31    let result = hasher.finalize();
32    let mut output = [0u8; 32];
33    output.copy_from_slice(&result);
34    output
35}
36
37/// Computes the SHA3-256 hash of the input.
38///
39/// This is used for Ed25519 signatures and authentication key derivation.
40///
41/// # Example
42///
43/// ```rust
44/// use aptos_sdk::crypto::sha3_256;
45///
46/// let hash = sha3_256(b"hello world");
47/// assert_eq!(hash.len(), 32);
48/// ```
49pub fn sha3_256(data: &[u8]) -> [u8; 32] {
50    let mut hasher = sha3::Sha3_256::new();
51    hasher.update(data);
52    let result = hasher.finalize();
53    let mut output = [0u8; 32];
54    output.copy_from_slice(&result);
55    output
56}
57
58/// Computes the SHA3-256 hash of multiple byte slices.
59#[allow(dead_code)] // Public API for users
60pub fn sha3_256_of<I, T>(items: I) -> [u8; 32]
61where
62    I: IntoIterator<Item = T>,
63    T: AsRef<[u8]>,
64{
65    let mut hasher = sha3::Sha3_256::new();
66    for item in items {
67        hasher.update(item.as_ref());
68    }
69    let result = hasher.finalize();
70    let mut output = [0u8; 32];
71    output.copy_from_slice(&result);
72    output
73}
74
75/// Computes a domain-separated hash for transaction signing.
76///
77/// This is used to create the signing message for transactions:
78/// SHA3-256(domain_separator || `bcs_bytes`)
79#[allow(dead_code)] // Public API for users
80pub fn signing_message(domain: &str, bcs_bytes: &[u8]) -> [u8; 32] {
81    sha3_256_of([format!("APTOS::{domain}").as_bytes(), bcs_bytes])
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87
88    #[test]
89    fn test_sha2_256() {
90        let hash = sha2_256(b"hello world");
91        assert_eq!(hash.len(), 32);
92        // Known hash value
93        let expected =
94            hex::decode("b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9")
95                .unwrap();
96        assert_eq!(hash.as_slice(), expected.as_slice());
97    }
98
99    #[test]
100    fn test_sha3_256() {
101        let hash = sha3_256(b"hello world");
102        assert_eq!(hash.len(), 32);
103        // Verify it's different from SHA2-256
104        let sha2_hash = sha2_256(b"hello world");
105        assert_ne!(hash, sha2_hash);
106    }
107
108    #[test]
109    fn test_sha3_256_of_multiple() {
110        let hash1 = sha3_256(b"helloworld");
111        let hash2 = sha3_256_of([b"hello".as_slice(), b"world".as_slice()]);
112        assert_eq!(hash1, hash2);
113    }
114
115    #[test]
116    fn test_signing_message() {
117        let msg = signing_message("RawTransaction", b"transaction_bytes");
118        assert_eq!(msg.len(), 32);
119    }
120}