1const IV: [u32; 8] = [
15 0x7380_166f,
16 0x4914_b2b9,
17 0x1724_42d7,
18 0xda8a_0600,
19 0xa96f_30bc,
20 0x1631_38aa,
21 0xe38d_ee4d,
22 0xb0fb_0e4e,
23];
24
25#[inline]
27fn p0(x: u32) -> u32 {
28 x ^ x.rotate_left(9) ^ x.rotate_left(17)
29}
30
31#[inline]
33fn p1(x: u32) -> u32 {
34 x ^ x.rotate_left(15) ^ x.rotate_left(23)
35}
36
37pub fn sm3(data: &[u8]) -> [u8; 32] {
39 let mut v = IV;
40
41 let bit_len = (data.len() as u64).wrapping_mul(8);
43 let mut msg = data.to_vec();
44 msg.push(0x80);
45 while msg.len() % 64 != 56 {
46 msg.push(0x00);
47 }
48 msg.extend_from_slice(&bit_len.to_be_bytes());
49
50 for block in msg.chunks_exact(64) {
52 compress(&mut v, block);
53 }
54
55 let mut out = [0u8; 32];
56 for (i, word) in v.iter().enumerate() {
57 out[i * 4..i * 4 + 4].copy_from_slice(&word.to_be_bytes());
58 }
59 out
60}
61
62fn compress(v: &mut [u32; 8], block: &[u8]) {
64 let mut w = [0u32; 68];
66 for i in 0..16 {
67 w[i] = u32::from_be_bytes([
68 block[i * 4],
69 block[i * 4 + 1],
70 block[i * 4 + 2],
71 block[i * 4 + 3],
72 ]);
73 }
74 for i in 16..68 {
75 w[i] = p1(w[i - 16] ^ w[i - 9] ^ w[i - 3].rotate_left(15))
76 ^ w[i - 13].rotate_left(7)
77 ^ w[i - 6];
78 }
79 let mut w1 = [0u32; 64];
80 for i in 0..64 {
81 w1[i] = w[i] ^ w[i + 4];
82 }
83
84 let [mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut h] = *v;
85
86 for j in 0..64 {
87 let t = if j < 16 {
89 0x79cc_4519u32
90 } else {
91 0x7a87_9d8au32
92 };
93 let ss1 = a
94 .rotate_left(12)
95 .wrapping_add(e)
96 .wrapping_add(t.rotate_left(j as u32))
97 .rotate_left(7);
98 let ss2 = ss1 ^ a.rotate_left(12);
99 let (ff, gg) = if j < 16 {
101 (a ^ b ^ c, e ^ f ^ g)
102 } else {
103 ((a & b) | (a & c) | (b & c), (e & f) | (!e & g))
104 };
105 let tt1 = ff.wrapping_add(d).wrapping_add(ss2).wrapping_add(w1[j]);
106 let tt2 = gg.wrapping_add(h).wrapping_add(ss1).wrapping_add(w[j]);
107 d = c;
108 c = b.rotate_left(9);
109 b = a;
110 a = tt1;
111 h = g;
112 g = f.rotate_left(19);
113 f = e;
114 e = p0(tt2);
115 }
116
117 v[0] ^= a;
118 v[1] ^= b;
119 v[2] ^= c;
120 v[3] ^= d;
121 v[4] ^= e;
122 v[5] ^= f;
123 v[6] ^= g;
124 v[7] ^= h;
125}
126
127const B64: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
129
130pub fn base64_encode(data: &[u8]) -> String {
132 let mut out = String::with_capacity(data.len().div_ceil(3) * 4);
133 for chunk in data.chunks(3) {
134 let b0 = chunk[0] as usize;
135 let b1 = chunk.get(1).copied().unwrap_or(0) as usize;
136 let b2 = chunk.get(2).copied().unwrap_or(0) as usize;
137 out.push(B64[b0 >> 2] as char);
138 out.push(B64[((b0 & 0x03) << 4) | (b1 >> 4)] as char);
139 out.push(if chunk.len() > 1 {
140 B64[((b1 & 0x0f) << 2) | (b2 >> 6)] as char
141 } else {
142 '='
143 });
144 out.push(if chunk.len() > 2 {
145 B64[b2 & 0x3f] as char
146 } else {
147 '='
148 });
149 }
150 out
151}
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156
157 #[test]
159 fn sm3_abc() {
160 let digest = sm3(b"abc");
161 let hex: String = digest.iter().map(|b| format!("{b:02x}")).collect();
162 assert_eq!(
163 hex,
164 "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0"
165 );
166 }
167
168 #[test]
170 fn sm3_long() {
171 let data = b"abcd".repeat(16);
172 let digest = sm3(&data);
173 let hex: String = digest.iter().map(|b| format!("{b:02x}")).collect();
174 assert_eq!(
175 hex,
176 "debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732"
177 );
178 }
179
180 #[test]
181 fn base64_basic() {
182 assert_eq!(base64_encode(b""), "");
183 assert_eq!(base64_encode(b"f"), "Zg==");
184 assert_eq!(base64_encode(b"fo"), "Zm8=");
185 assert_eq!(base64_encode(b"foo"), "Zm9v");
186 assert_eq!(base64_encode(b"foobar"), "Zm9vYmFy");
187 }
188
189 #[test]
191 fn checkvalue_form() {
192 let cv = base64_encode(&sm3(b"hello"));
194 assert_eq!(cv.len(), 44);
195 assert!(cv.ends_with('='));
196 }
197}