Merge vk-gl-cts/vulkan-cts-1.0.1 into vk-gl-cts/vulkan-cts-1.0.2
[platform/upstream/VK-GL-CTS.git] / framework / delibs / debase / deSha1.c
1 /*-------------------------------------------------------------------------
2  * drawElements Base Portability Library
3  * -------------------------------------
4  *
5  * Copyright 2015 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief SHA1 hash functions.
22  *//*--------------------------------------------------------------------*/
23
24 #include "deSha1.h"
25
26 #include "deMemory.h"
27
28 DE_BEGIN_EXTERN_C
29
30 enum
31 {
32         CHUNK_BIT_SIZE  = 512,
33         CHUNK_BYTE_SIZE = CHUNK_BIT_SIZE / 8
34 };
35
36 static deUint32 leftRotate (deUint32 val, deUint32 count)
37 {
38         DE_ASSERT(count < 32);
39
40         return (val << count) | (val >> (32 - count));
41 }
42
43 void deSha1Stream_init (deSha1Stream* stream)
44 {
45         stream->size = 0;
46
47         /* Set the initial 16 deUint32s that contain real data to zeros. */
48         deMemset(stream->data, 0, 16 * sizeof(deUint32));
49
50         stream->hash[0] = 0x67452301u;
51         stream->hash[1] = 0xEFCDAB89u;
52         stream->hash[2] = 0x98BADCFEu;
53         stream->hash[3] = 0x10325476u;
54         stream->hash[4] = 0xC3D2E1F0u;
55 }
56
57 static void deSha1Stream_flushChunk (deSha1Stream* stream)
58 {
59         DE_ASSERT(stream->size % CHUNK_BYTE_SIZE == 0 && stream->size > 0);
60
61         {
62                 size_t ndx;
63
64                 /* Expand the 16 uint32s that contain the data to 80. */
65                 for (ndx = 16; ndx < DE_LENGTH_OF_ARRAY(stream->data); ndx++)
66                 {
67                         stream->data[ndx] = leftRotate(stream->data[ndx - 3]
68                                                                                    ^ stream->data[ndx - 8]
69                                                                                    ^ stream->data[ndx - 14]
70                                                                                    ^ stream->data[ndx - 16], 1);
71                 }
72         }
73
74         {
75                 deUint32        a = stream->hash[0];
76                 deUint32        b = stream->hash[1];
77                 deUint32        c = stream->hash[2];
78                 deUint32        d = stream->hash[3];
79                 deUint32        e = stream->hash[4];
80                 size_t          ndx;
81
82                 for (ndx = 0; ndx < DE_LENGTH_OF_ARRAY(stream->data); ndx++)
83                 {
84                         deUint32 f;
85                         deUint32 k;
86
87                         if (ndx < 20)
88                         {
89                                 f = (b & c) | ((~b) & d);
90                                 k = 0x5A827999u;
91                         }
92                         else if (ndx < 40)
93                         {
94                                 f = b ^ c ^ d;
95                                 k = 0x6ED9EBA1u;
96                         }
97                         else if (ndx < 60)
98                         {
99                                 f = (b & c) | (b & d) | (c & d);
100                                 k = 0x8F1BBCDCu;
101                         }
102                         else
103                         {
104                                 f = b ^ c ^ d;
105                                 k = 0xCA62C1D6u;
106                         }
107
108                         {
109                                 const deUint32 tmp = leftRotate(a, 5) + f + e + k + stream->data[ndx];
110
111                                 e = d;
112                                 d = c;
113                                 c = leftRotate(b, 30);
114                                 b = a;
115                                 a = tmp;
116                         }
117                 }
118
119                 stream->hash[0] += a;
120                 stream->hash[1] += b;
121                 stream->hash[2] += c;
122                 stream->hash[3] += d;
123                 stream->hash[4] += e;
124
125                 /* Set the initial 16 deUint32s that contain the real data to zeros. */
126                 deMemset(stream->data, 0, 16 * sizeof(deUint32));
127         }
128 }
129
130 void deSha1Stream_process (deSha1Stream* stream, size_t size, const void* data_)
131 {
132         const deUint8* const    data                    = (const deUint8*)data_;
133         size_t                                  bytesProcessed  = 0;
134
135         while (bytesProcessed < size)
136         {
137                 do
138                 {
139                         const size_t bitOffset = (size_t)(8 * (4 - (1 + (stream->size % 4))));
140
141                         stream->data[(stream->size / 4) % 16] |= ((deUint32)data[bytesProcessed]) << (deUint32)bitOffset;
142
143                         stream->size++;
144                         bytesProcessed++;
145                 }
146                 while (stream->size % CHUNK_BYTE_SIZE != 0 && bytesProcessed < size);
147
148                 if (stream->size % CHUNK_BYTE_SIZE == 0)
149                         deSha1Stream_flushChunk(stream);
150         }
151
152         DE_ASSERT(bytesProcessed == size);
153 }
154
155 void deSha1Stream_finalize (deSha1Stream* stream, deSha1* hash)
156 {
157         /* \note First element is initialized to 0x80u and rest to 0x0. */
158         static const deUint8    padding[CHUNK_BYTE_SIZE]        = { 0x80u };
159         const deUint64                  length                                          = stream->size * 8;
160         deUint8                                 lengthData[sizeof(deUint64)];
161         size_t                                  ndx;
162
163         DE_ASSERT(padding[0] == 0x80u);
164         DE_ASSERT(padding[1] == 0x0u);
165
166         for (ndx = 0; ndx < sizeof(deUint64); ndx++)
167                 lengthData[ndx] = (deUint8)(0xffu & (length >> (8 * (sizeof(deUint64) - 1 - ndx))));
168
169         {
170                 const deUint64 spaceLeftInChunk = CHUNK_BYTE_SIZE - (stream->size % CHUNK_BYTE_SIZE);
171
172                 if (spaceLeftInChunk >= 1 + sizeof(lengthData))
173                         deSha1Stream_process(stream, (size_t)(spaceLeftInChunk - sizeof(lengthData)), padding);
174                 else
175                         deSha1Stream_process(stream, (size_t)(CHUNK_BYTE_SIZE - (sizeof(lengthData)) - spaceLeftInChunk), padding);
176         }
177
178         deSha1Stream_process(stream, sizeof(lengthData), lengthData);
179         DE_ASSERT(stream->size % CHUNK_BYTE_SIZE == 0);
180
181         deMemcpy(hash->hash, stream->hash, sizeof(hash->hash));
182 }
183
184 void deSha1_compute (deSha1* hash, size_t size, const void* data)
185 {
186         deSha1Stream stream;
187
188         deSha1Stream_init(&stream);
189         deSha1Stream_process(&stream, size, data);
190         deSha1Stream_finalize(&stream, hash);
191 }
192
193 void deSha1_render (const deSha1* hash, char* buffer)
194 {
195         size_t charNdx;
196
197         for (charNdx = 0; charNdx < 40; charNdx++)
198         {
199                 const deUint32  val32   = hash->hash[charNdx / 8];
200                 const deUint8   val8    = (deUint8)(0x0fu & (val32 >> (4 * (8 - 1 - (charNdx % 8)))));
201
202                 if (val8 < 10)
203                         buffer[charNdx] = (char)('0' + val8);
204                 else
205                         buffer[charNdx] = (char)('a' + val8 - 10);
206         }
207 }
208
209 deBool deSha1_parse (deSha1* hash, const char* buffer)
210 {
211         size_t charNdx;
212
213         deMemset(hash->hash, 0, sizeof(hash->hash));
214
215         for (charNdx = 0; charNdx < 40; charNdx++)
216         {
217                 deUint8 val4;
218
219                 if (buffer[charNdx] >= '0' && buffer[charNdx] <= '9')
220                         val4 = (deUint8)(buffer[charNdx] - '0');
221                 else if (buffer[charNdx] >= 'a' && buffer[charNdx] <= 'f')
222                         val4 = (deUint8)(10 + (buffer[charNdx] - 'a'));
223                 else if (buffer[charNdx] >= 'A' && buffer[charNdx] <= 'F')
224                         val4 = (deUint8)(10 + (buffer[charNdx] - 'A'));
225                 else
226                         return DE_FALSE;
227
228                 hash->hash[charNdx / 8] |= ((deUint32)val4) << (4 * (8u - 1u - (charNdx % 8u)));
229         }
230
231         return DE_TRUE;
232 }
233
234 deBool deSha1_equal (const deSha1* a, const deSha1* b)
235 {
236         /* \note deMemcmp() can only be used for equality. It doesn't provide correct ordering between hashes. */
237         return deMemCmp(a->hash, b->hash, sizeof(b->hash)) == 0;
238 }
239
240 void deSha1_selfTest (void)
241 {
242         const char* const validHashStrings[] =
243         {
244                 "ac890cfca05717c05dc831996b2289251da2984e",
245                 "0f87ba807acb3e6effe617249f30453a524a2ea3",
246                 "6f483cc3fa820e58ed9f83c83bdf8d213293b3ad"
247         };
248
249         const char* const invalidHashStrings[] =
250         {
251                 " c890cfca05717c05dc831996b2289251da2984e",
252                 "0f87ba807acb3e6 ffe617249f30453a524a2ea3",
253                 "6f483cc3fa820e58ed9f83c83bdf8d213293b3a ",
254
255                 "mc890cfca05717c05dc831996b2289251da2984e",
256                 "0f87ba807acb3e6effe617249fm0453a524a2ea3",
257                 "6f483cc3fa820e58ed9f83c83bdf8d213293b3an",
258
259                 "ac890cfca05717c05dc83\n996b2289251da2984e",
260                 "0f87ba807acb3e6effe617\t49f30453a524a2ea3",
261                 "ac890cfca05717c05dc831\096b2289251da2984e",
262                 "6f483cc3fa{20e58ed9f83c83bdf8d213293b3ad"
263         };
264
265         const struct
266         {
267                 const char* const hash;
268                 const char* const data;
269         } stringHashPairs[] =
270         {
271                 /* Generated using sha1sum. */
272                 { "da39a3ee5e6b4b0d3255bfef95601890afd80709", "" },
273                 { "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d", "hello" },
274                 { "ec1919e856540f42bd0e6f6c1ffe2fbd73419975",
275                         "Cherry is a browser-based GUI for controlling deqp test runs and analysing the test results."
276                 }
277         };
278
279         const int garbage = 0xde;
280
281         /* Test parsing valid sha1 strings. */
282         {
283                 size_t stringNdx;
284
285                 for (stringNdx = 0; stringNdx < DE_LENGTH_OF_ARRAY(validHashStrings); stringNdx++)
286                 {
287                         deSha1 hash;
288                         deMemset(&hash, garbage, sizeof(deSha1));
289                         DE_TEST_ASSERT(deSha1_parse(&hash, validHashStrings[stringNdx]));
290                 }
291         }
292
293         /* Test parsing invalid sha1 strings. */
294         {
295                 size_t stringNdx;
296
297                 for (stringNdx = 0; stringNdx < DE_LENGTH_OF_ARRAY(invalidHashStrings); stringNdx++)
298                 {
299                         deSha1 hash;
300                         deMemset(&hash, garbage, sizeof(deSha1));
301                         DE_TEST_ASSERT(!deSha1_parse(&hash, invalidHashStrings[stringNdx]));
302                 }
303         }
304
305         /* Compare valid hash strings for equality. */
306         {
307                 size_t stringNdx;
308
309                 for (stringNdx = 0; stringNdx < DE_LENGTH_OF_ARRAY(validHashStrings); stringNdx++)
310                 {
311                         deSha1 hashA;
312                         deSha1 hashB;
313
314                         deMemset(&hashA, garbage, sizeof(deSha1));
315                         deMemset(&hashB, garbage, sizeof(deSha1));
316
317                         DE_TEST_ASSERT(deSha1_parse(&hashA, validHashStrings[stringNdx]));
318                         DE_TEST_ASSERT(deSha1_parse(&hashB, validHashStrings[stringNdx]));
319
320                         DE_TEST_ASSERT(deSha1_equal(&hashA, &hashA));
321                         DE_TEST_ASSERT(deSha1_equal(&hashA, &hashB));
322                         DE_TEST_ASSERT(deSha1_equal(&hashB, &hashA));
323                 }
324         }
325
326         /* Compare valid different hash strings for equality. */
327         {
328                 size_t stringANdx;
329                 size_t stringBNdx;
330
331                 for (stringANdx = 0; stringANdx < DE_LENGTH_OF_ARRAY(validHashStrings); stringANdx++)
332                 for (stringBNdx = 0; stringBNdx < DE_LENGTH_OF_ARRAY(validHashStrings); stringBNdx++)
333                 {
334                         deSha1 hashA;
335                         deSha1 hashB;
336
337                         if (stringANdx == stringBNdx)
338                                 continue;
339
340                         deMemset(&hashA, garbage, sizeof(deSha1));
341                         deMemset(&hashB, garbage, sizeof(deSha1));
342
343                         DE_TEST_ASSERT(deSha1_parse(&hashA, validHashStrings[stringANdx]));
344                         DE_TEST_ASSERT(deSha1_parse(&hashB, validHashStrings[stringBNdx]));
345
346                         DE_TEST_ASSERT(!deSha1_equal(&hashA, &hashB));
347                         DE_TEST_ASSERT(!deSha1_equal(&hashB, &hashA));
348                 }
349         }
350
351         /* Test rendering hash as string. */
352         {
353                 size_t stringNdx;
354
355                 for (stringNdx = 0; stringNdx < DE_LENGTH_OF_ARRAY(validHashStrings); stringNdx++)
356                 {
357                         char    result[40];
358                         deSha1  hash;
359
360                         deMemset(&hash, garbage, sizeof(hash));
361                         deMemset(&result, garbage, sizeof(result));
362
363                         DE_TEST_ASSERT(deSha1_parse(&hash, validHashStrings[stringNdx]));
364                         deSha1_render(&hash, result);
365
366                         DE_TEST_ASSERT(strncmp(result, validHashStrings[stringNdx], 40) == 0);
367                 }
368         }
369
370         /* Test hash against few pre-computed cases. */
371         {
372                 size_t ndx;
373
374                 for (ndx = 0; ndx < DE_LENGTH_OF_ARRAY(stringHashPairs); ndx++)
375                 {
376                         deSha1 result;
377                         deSha1 reference;
378
379                         deSha1_compute(&result, strlen(stringHashPairs[ndx].data),  stringHashPairs[ndx].data);
380                         DE_TEST_ASSERT(deSha1_parse(&reference, stringHashPairs[ndx].hash));
381
382                         DE_TEST_ASSERT(deSha1_equal(&reference, &result));
383                 }
384         }
385
386         /* Test hash stream against few pre-computed cases. */
387         {
388                 size_t ndx;
389
390                 for (ndx = 0; ndx < DE_LENGTH_OF_ARRAY(stringHashPairs); ndx++)
391                 {
392                         const char* const       data    = stringHashPairs[ndx].data;
393                         const size_t            size    = strlen(data);
394
395                         deSha1Stream            stream;
396                         deSha1                          result;
397                         deSha1                          reference;
398
399                         deSha1Stream_init(&stream);
400
401                         deSha1Stream_process(&stream, size/2, data);
402                         deSha1Stream_process(&stream, size - (size/2), data + size/2);
403
404                         deSha1Stream_finalize(&stream, &result);
405
406                         deSha1_compute(&result, strlen(stringHashPairs[ndx].data),  stringHashPairs[ndx].data);
407                         DE_TEST_ASSERT(deSha1_parse(&reference, stringHashPairs[ndx].hash));
408
409                         DE_TEST_ASSERT(deSha1_equal(&reference, &result));
410                 }
411         }
412 }
413
414 DE_END_EXTERN_C