1use sha2::Digest as Sha2Digest;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum HashFunction {
10 Sha2_256,
12 Sha3_256,
14}
15
16pub fn sha2_256(data: &[u8]) -> [u8; 32] {
31 let mut hasher = sha2::Sha256::new();
32 hasher.update(data);
33 let result = hasher.finalize();
34 let mut output = [0u8; 32];
35 output.copy_from_slice(&result);
36 output
37}
38
39pub fn sha3_256(data: &[u8]) -> [u8; 32] {
52 let mut hasher = sha3::Sha3_256::new();
53 hasher.update(data);
54 let result = hasher.finalize();
55 let mut output = [0u8; 32];
56 output.copy_from_slice(&result);
57 output
58}
59
60#[allow(dead_code)] pub fn sha3_256_of<I, T>(items: I) -> [u8; 32]
63where
64 I: IntoIterator<Item = T>,
65 T: AsRef<[u8]>,
66{
67 let mut hasher = sha3::Sha3_256::new();
68 for item in items {
69 hasher.update(item.as_ref());
70 }
71 let result = hasher.finalize();
72 let mut output = [0u8; 32];
73 output.copy_from_slice(&result);
74 output
75}
76
77#[allow(dead_code)] pub fn signing_message(domain: &str, bcs_bytes: &[u8]) -> Vec<u8> {
91 let prefix = sha3_256(format!("APTOS::{domain}").as_bytes());
92 let mut message = Vec::with_capacity(prefix.len() + bcs_bytes.len());
93 message.extend_from_slice(&prefix);
94 message.extend_from_slice(bcs_bytes);
95 message
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102 #[test]
103 fn test_sha2_256() {
104 let hash = sha2_256(b"hello world");
105 assert_eq!(hash.len(), 32);
106 let expected =
108 const_hex::decode("b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9")
109 .unwrap();
110 assert_eq!(hash.as_slice(), expected.as_slice());
111 }
112
113 #[test]
114 fn test_sha3_256() {
115 let hash = sha3_256(b"hello world");
116 assert_eq!(hash.len(), 32);
117 let sha2_hash = sha2_256(b"hello world");
119 assert_ne!(hash, sha2_hash);
120 }
121
122 #[test]
123 fn test_sha3_256_of_multiple() {
124 let hash1 = sha3_256(b"helloworld");
125 let hash2 = sha3_256_of([b"hello".as_slice(), b"world".as_slice()]);
126 assert_eq!(hash1, hash2);
127 }
128
129 #[test]
130 fn test_signing_message() {
131 let bcs_bytes = b"transaction_bytes";
132 let msg = signing_message("RawTransaction", bcs_bytes);
133
134 let expected_prefix = sha3_256(b"APTOS::RawTransaction");
137 assert_eq!(msg.len(), 32 + bcs_bytes.len());
138 assert_eq!(&msg[..32], &expected_prefix[..]);
139 assert_eq!(&msg[32..], bcs_bytes);
140
141 let single_hash = sha3_256_of([b"APTOS::RawTransaction".as_slice(), bcs_bytes]);
143 assert_ne!(&msg[..32], &single_hash[..]);
144 }
145
146 #[test]
147 fn test_signing_message_known_bytes() {
148 let expected = const_hex::decode(
152 "b5e97db07fa0bd0e5598aa3643a9bc6f6693bddc1a9fec9e674a461eaa00b193aabb",
153 )
154 .unwrap();
155 let msg = signing_message("RawTransaction", &[0xaa, 0xbb]);
156 assert_eq!(msg, expected);
157 }
158}