libxcks  0.1.0.1
sm3.cpp
Go to the documentation of this file.
1 /*
2  * libxcks
3  * Copyright (C) 2022 Julien Couot
4  *
5  * This program is free software: you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or (at your
8  * option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
13  * License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program. If not, see <https://www.gnu.org/licenses/>.
17  */
18 
24 //---------------------------------------------------------------------------
25 #include <cstring>
26 
27 #include "sm3.hpp"
28 //---------------------------------------------------------------------------
29 
31 using namespace std;
32 //---------------------------------------------------------------------------
33 
34 
35 namespace libxcks
36 {
38 
39 inline void SM3::transformBlock(uint32_t* digest, uint8_t* input)
40 {
41  uint32_t W[68];
42  uint32_t W1[64];
43 
44  for (uint8_t j = 0, i = 0; j < 64; ++j, i += 4)
45  {
46  W[j] = (input[i] << 24) | (input[i + 1] << 16) | (input[i + 2] << 8) | input[i + 3];
47  }
48 
49  for (uint8_t j = 16; j < 68; ++j)
50  {
51  uint32_t wj3 = W[j - 3];
52  uint32_t r15 = rotleft(wj3, 15);
53  uint32_t wj13 = W[j - 13];
54  uint32_t r7 = rotleft(wj13, 7);
55  W[j] = p1(W[j - 16] ^ W[j - 9] ^ r15) ^ r7 ^ W[j - 6];
56  }
57 
58  for (uint8_t j = 0; j < 64; ++j)
59  {
60  W1[j] = W[j] ^ W[j + 4];
61  }
62 
63  uint32_t A = digest[0];
64  uint32_t B = digest[1];
65  uint32_t C = digest[2];
66  uint32_t D = digest[3];
67  uint32_t E = digest[4];
68  uint32_t F = digest[5];
69  uint32_t G = digest[6];
70  uint32_t H = digest[7];
71 
72  for (uint8_t j = 0; j < 16; ++j)
73  {
74  uint32_t a12 = rotleft(A, 12);
75  uint32_t s1 = a12 + E + rotleft(T0, j);
76  uint32_t SS1 = rotleft(s1, 7);
77  uint32_t SS2 = SS1 ^ a12;
78  uint32_t TT1 = FF0(A, B, C) + D + SS2 + W1[j];
79  uint32_t TT2 = GG0(E, F, G) + H + SS1 + W[j];
80 
81  D = C;
82  C = rotleft(B, 9);
83  B = A;
84  A = TT1;
85  H = G;
86  G = rotleft(F, 19);
87  F = E;
88  E = p0(TT2);
89  }
90 
91  for (uint8_t j = 16; j < 64; ++j)
92  {
93  uint32_t a12 = rotleft(A, 12);
94  uint32_t s1 = a12 + E + rotleft(T1, (j % 32));
95  uint32_t SS1 = rotleft(s1, 7);
96  uint32_t SS2 = SS1 ^ a12;
97  uint32_t TT1 = FF1(A, B, C) + D + SS2 + W1[j];
98  uint32_t TT2 = GG1(E, F, G) + H + SS1 + W[j];
99 
100  D = C;
101  C = rotleft(B, 9);
102  B = A;
103  A = TT1;
104  H = G;
105  G = rotleft(F, 19);
106  F = E;
107  E = p0(TT2);
108  }
109 
110  digest[0] ^= A;
111  digest[1] ^= B;
112  digest[2] ^= C;
113  digest[3] ^= D;
114  digest[4] ^= E;
115  digest[5] ^= F;
116  digest[6] ^= G;
117  digest[7] ^= H;
118 }
119 //---------------------------------------------------------------------------
120 
121 
122 void SM3::finalize(uint8_t* output)
123 {
124  uint8_t* local = reinterpret_cast<uint8_t*>(workspace);
125  addwc(&processed_high, &processed_low, workspace_used);
126 
127  local[workspace_used++] = 0x80;
128 
129  if (workspace_used > SM3_PAD_SIZE)
130  {
131  memset(&local[workspace_used], 0, SM3_BLOCK_SIZE - workspace_used);
132  workspace_used += SM3_BLOCK_SIZE - workspace_used;
133 
134  transformBlock(digest, local);
135  workspace_used = 0;
136  }
137 
138  memset(&local[workspace_used], 0, SM3_PAD_SIZE - workspace_used);
139 
140  uint32_t processed_bits_high = swap(processed_high << 3 | ((processed_low >> 29) & 0x07));
141  memcpy(&local[SM3_PAD_SIZE], &processed_bits_high, sizeof(uint32_t));
142 
143  uint32_t processed_bits_low = swap(processed_low << 3);
144  memcpy(&local[SM3_PAD_SIZE + sizeof(uint32_t)], &processed_bits_low, sizeof(uint32_t));
145 
146  transformBlock(digest, local);
147 
148  uint8_t* temp = output;
149  for (uint8_t j = 0; j < (SM3_DIGEST_SIZE / sizeof(uint32_t)); ++j)
150  {
151  *temp++ = (digest[j]) >> 24;
152  *temp++ = (digest[j]) >> 16;
153  *temp++ = (digest[j]) >> 8;
154  *temp++ = (digest[j]);
155  digest[j] = 0;
156  workspace[j] = 0;
157  }
158  for (uint8_t j = 8; j < (SM3_BLOCK_SIZE / sizeof(uint32_t)); ++j)
159  {
160  workspace[j] = 0;
161  }
162  workspace_used = 0;
163  processed_low = 0;
164  processed_high = 0;
165 }
166 //---------------------------------------------------------------------------
167 
168 
169 /*
170  * Default constructor.
171  */
172 SM3::SM3()
173 {
174  reset();
175 }
176 //---------------------------------------------------------------------------
177 
178 
179 /*
180  * Resets the SM3 hash to initial value.
181  */
182 void SM3::reset()
183 {
184  digest[0] = 0x7380166F;
185  digest[1] = 0x4914B2B9;
186  digest[2] = 0x172442D7;
187  digest[3] = 0xDA8A0600;
188  digest[4] = 0xA96F30BC;
189  digest[5] = 0x163138AA;
190  digest[6] = 0xE38DEE4D;
191  digest[7] = 0xB0FB0E4E;
192 
193  for (size_t j = 0; j < (SM3_BLOCK_SIZE / sizeof(uint32_t)); j++)
194  {
195  workspace[j] = 0;
196  }
197  workspace_used = 0;
198  processed_high = 0;
199  processed_low = 0;
200 }
201 //---------------------------------------------------------------------------
202 
203 
204 /*
205  * Updates the SM3 hash with specified array of bytes.
206  */
207 void SM3::update(const uint8_t* buf, size_t len)
208 {
209  uint8_t* local = reinterpret_cast<uint8_t*>(workspace);
210 
211  while (len)
212  {
213  uint32_t add = min(len, SM3_BLOCK_SIZE - workspace_used);
214 
215  memcpy(&local[workspace_used], buf, add);
216 
217  workspace_used += add;
218  buf += add;
219  len -= add;
220 
221  if(workspace_used == SM3_BLOCK_SIZE)
222  {
223  transformBlock(digest, local);
224  addwc(&processed_high, &processed_low, SM3_BLOCK_SIZE);
225  workspace_used = 0;
226  }
227  }
228 }
229 //---------------------------------------------------------------------------
230 
231 
232 /*
233  * Returns the BLAKE3 hash value in the first 32 bytes of the given address.
234  */
235 uint8_t* SM3::getValue(uint8_t* buffer) const
236 {
237  SM3 sm3(*this);
238  sm3.finalize(static_cast<uint8_t*>(buffer));
239 
240  return buffer;
241 }
242 //---------------------------------------------------------------------------
243 
245 } // namespace libxcks
246 //---------------------------------------------------------------------------
#define F(x, y, z)
Helper function for MD4's computing.
#define G(x, y, z)
Helper function for MD4's computing.
#define H(x, y, z)
Helper function for MD4's computing.
Compute SM3 hash.
@ SM3
SM3 cryptographic hash function.