20 classVariableNames:'' |
20 classVariableNames:'' |
21 poolDictionaries:'' |
21 poolDictionaries:'' |
22 category:'System-Crypt-Hashing' |
22 category:'System-Crypt-Hashing' |
23 ! |
23 ! |
24 |
24 |
|
25 CRC32Stream subclass:#CRC32Stream_Castagnoli |
|
26 instanceVariableNames:'' |
|
27 classVariableNames:'' |
|
28 poolDictionaries:'' |
|
29 privateIn:CRC32Stream |
|
30 ! |
|
31 |
|
32 !CRC32Stream primitiveDefinitions! |
|
33 %{ |
|
34 |
|
35 /* |
|
36 * includes, defines, structure definitions |
|
37 * and typedefs come here. |
|
38 */ |
|
39 #ifdef __LP64__ |
|
40 inline uint64_t _mm_crc32_u64(uint64_t crc, uint64_t value) { |
|
41 asm("crc32q %[value], %[crc]\n" : [crc] "+r" (crc) : [value] "rm" (value)); |
|
42 return crc; |
|
43 } |
|
44 #endif |
|
45 |
|
46 inline uint32_t _mm_crc32_u32(uint32_t crc, uint32_t value) { |
|
47 asm("crc32l %[value], %[crc]\n" : [crc] "+r" (crc) : [value] "rm" (value)); |
|
48 return crc; |
|
49 } |
|
50 |
|
51 inline uint32_t _mm_crc32_u16(uint32_t crc, uint16_t value) { |
|
52 asm("crc32w %[value], %[crc]\n" : [crc] "+r" (crc) : [value] "rm" (value)); |
|
53 return crc; |
|
54 } |
|
55 |
|
56 inline uint32_t _mm_crc32_u8(uint32_t crc, uint8_t value) { |
|
57 asm("crc32b %[value], %[crc]\n" : [crc] "+r" (crc) : [value] "rm" (value)); |
|
58 return crc; |
|
59 } |
|
60 %} |
|
61 ! ! |
|
62 |
25 !CRC32Stream class methodsFor:'documentation'! |
63 !CRC32Stream class methodsFor:'documentation'! |
26 |
64 |
27 copyright |
65 copyright |
28 " |
66 " |
29 COPYRIGHT (c) 2003 by eXept Software AG |
67 COPYRIGHT (c) 2003 by eXept Software AG |
127 Transcript show:'crc32:'; showCR: hashStream hashValue hexPrintString. |
168 Transcript show:'crc32:'; showCR: hashStream hashValue hexPrintString. |
128 Transcript show:t; show:' seconds for '; show:(50*n/1024) asFloat; showCR:' Kb'. |
169 Transcript show:t; show:' seconds for '; show:(50*n/1024) asFloat; showCR:' Kb'. |
129 Transcript show:(n*50/1024 / t); showCR:' Kb/s' |
170 Transcript show:(n*50/1024 / t); showCR:' Kb/s' |
130 [exEnd] |
171 [exEnd] |
131 |
172 |
|
173 500Mb/s (on MacBook Pro 2012 / 2.6Ghz I7) |
|
174 [exBegin] |
|
175 |hashStream n t| |
|
176 |
|
177 hashStream := CRC32Stream newCastagnoli. |
|
178 n := 2000000. |
|
179 t := Time millisecondsToRun:[ |
|
180 n timesRepeat:[ |
|
181 hashStream nextPutAll:'12345678901234567890123456789012345678901234567890'. |
|
182 ]. |
|
183 ]. |
|
184 t := (t / 1000) asFloat. |
|
185 Transcript show:'crc32:'; showCR: hashStream hashValue hexPrintString. |
|
186 Transcript show:t; show:' seconds for '; show:(50*n/1024) asFloat; showCR:' Kb'. |
|
187 Transcript show:(n*50/1024 / t); showCR:' Kb/s' |
|
188 [exEnd] |
|
189 |
132 test vectors from https://tools.ietf.org/html/rfc3720#page-217: |
190 test vectors from https://tools.ietf.org/html/rfc3720#page-217: |
133 |
191 |
134 expect 0 |
192 expect 0 |
135 [exBegin] |
193 [exBegin] |
136 self information:(CRC32Stream newCrc32c hashValueOf:'') hexPrintString |
194 self information:(CRC32Stream newCrc32c hashValueOf:'') hexPrintString |
158 |
216 |
159 " |
217 " |
160 ! ! |
218 ! ! |
161 |
219 |
162 !CRC32Stream class methodsFor:'instance creation'! |
220 !CRC32Stream class methodsFor:'instance creation'! |
|
221 |
|
222 castagnoli_nextPutBytes:count from:anObject startingAt:start |
|
223 "add the hash of anObject to the computed hash so far. |
|
224 This uses an x86 crc instruction, |
|
225 and works only with the castagnoli polynom" |
|
226 |
|
227 %{ |
|
228 #if defined(__x86__) || defined(__x86_64__) |
|
229 # if defined(__clang__) || defined(__GNUC__) |
|
230 # pragma GCC push_options |
|
231 # pragma GCC target ("arch=core-avx2") |
|
232 |
|
233 if (__bothSmallInteger(count, start)) { |
|
234 int len, offs; |
|
235 int objSize; |
|
236 unsigned char *extPtr; |
|
237 |
|
238 len = __intVal(count); |
|
239 offs = __intVal(start) - 1; |
|
240 |
|
241 if (__isExternalBytesLike(anObject)) { |
|
242 OBJ sz = __externalBytesSize(anObject); |
|
243 |
|
244 extPtr = (unsigned char *)__externalBytesAddress(anObject); |
|
245 if (__isSmallInteger(sz)) { |
|
246 objSize = __intVal(sz); |
|
247 } else { |
|
248 objSize = 0; /* unknown */ |
|
249 } |
|
250 } else { |
|
251 int nInstVars, nInstBytes; |
|
252 OBJ oClass = __Class(anObject); |
|
253 |
|
254 switch (__intVal(__ClassInstPtr(oClass)->c_flags) & ARRAYMASK) { |
|
255 case BYTEARRAY: |
|
256 case WORDARRAY: |
|
257 case LONGARRAY: |
|
258 case SWORDARRAY: |
|
259 case SLONGARRAY: |
|
260 case FLOATARRAY: |
|
261 case DOUBLEARRAY: |
|
262 break; |
|
263 default: |
|
264 goto bad; |
|
265 } |
|
266 nInstVars = __intVal(__ClassInstPtr(oClass)->c_ninstvars); |
|
267 nInstBytes = __OBJS2BYTES__(nInstVars); |
|
268 // nInstBytes is the number of bytes occupied by pointer instance variables |
|
269 // subtract from size and add to byte-pointer |
|
270 objSize = __qSize(anObject) - OHDR_SIZE - nInstBytes; |
|
271 extPtr = (unsigned char *)__byteArrayVal(anObject)+nInstBytes; |
|
272 } |
|
273 |
|
274 if ((offs >= 0) && (len >= 0) && (objSize >= (len + offs))) { |
|
275 unsigned int _crc; |
|
276 unsigned int *_crcTable = __integerArrayVal( __INST(crcTable) ); |
|
277 unsigned char *cp = extPtr+offs; |
|
278 unsigned int n = len; |
|
279 |
|
280 if (__isSmallInteger(__INST(crc))) { |
|
281 _crc = (unsigned int) (__intVal( __INST(crc) )); |
|
282 } else { |
|
283 _crc = __unsignedLongIntVal( __INST(crc) ); |
|
284 } |
|
285 |
|
286 #if 0 |
|
287 # if __POINTER_SIZE__ == 8 |
|
288 if (((unsigned INT)cp & 7) == 0) { |
|
289 // longword aligned |
|
290 for ( ; n >= 8 ; n -= 8, cp += 8) { |
|
291 unsigned INT lWord; |
|
292 unsigned char _idx; |
|
293 |
|
294 lWord = ((unsigned INT *)cp)[0]; |
|
295 _idx = (_crc ^ lWord) & 0xFF; |
|
296 _crc = _crcTable[_idx] ^ (_crc >> 8); |
|
297 _idx = (_crc ^ (lWord>>8)) & 0xFF; |
|
298 _crc = _crcTable[_idx] ^ (_crc >> 8); |
|
299 _idx = (_crc ^ (lWord>>16)) & 0xFF; |
|
300 _crc = _crcTable[_idx] ^ (_crc >> 8); |
|
301 _idx = (_crc ^ (lWord>>24)) & 0xFF; |
|
302 _crc = _crcTable[_idx] ^ (_crc >> 8); |
|
303 |
|
304 _idx = (_crc ^ (lWord>>32)) & 0xFF; |
|
305 _crc = _crcTable[_idx] ^ (_crc >> 8); |
|
306 _idx = (_crc ^ (lWord>>40)) & 0xFF; |
|
307 _crc = _crcTable[_idx] ^ (_crc >> 8); |
|
308 _idx = (_crc ^ (lWord>>48)) & 0xFF; |
|
309 _crc = _crcTable[_idx] ^ (_crc >> 8); |
|
310 _idx = (_crc ^ (lWord>>56)) & 0xFF; |
|
311 _crc = _crcTable[_idx] ^ (_crc >> 8); |
|
312 } |
|
313 } |
|
314 # endif // __POINTER_SIZE__ == 8 |
|
315 if (((unsigned INT)cp & 3) == 0) { |
|
316 // word aligned |
|
317 for ( ; n >= 4 ; n -= 4, cp += 4) { |
|
318 unsigned int word; |
|
319 unsigned char _idx; |
|
320 |
|
321 word = ((unsigned int *)cp)[0]; |
|
322 _idx = (_crc ^ word) & 0xFF; |
|
323 _crc = _crcTable[_idx] ^ (_crc >> 8); |
|
324 _idx = (_crc ^ (word>>8)) & 0xFF; |
|
325 _crc = _crcTable[_idx] ^ (_crc >> 8); |
|
326 _idx = (_crc ^ (word>>16)) & 0xFF; |
|
327 _crc = _crcTable[_idx] ^ (_crc >> 8); |
|
328 _idx = (_crc ^ (word>>24)) & 0xFF; |
|
329 _crc = _crcTable[_idx] ^ (_crc >> 8); |
|
330 } |
|
331 } |
|
332 #endif // 0 |
|
333 for ( ; n >= 4 ; n -= 4, cp += 4) { |
|
334 unsigned char _idx; |
|
335 |
|
336 _idx = (_crc ^ cp[0]) & 0xFF; |
|
337 _crc = _crcTable[_idx] ^ (_crc >> 8); |
|
338 _idx = (_crc ^ cp[1]) & 0xFF; |
|
339 _crc = _crcTable[_idx] ^ (_crc >> 8); |
|
340 _idx = (_crc ^ cp[2]) & 0xFF; |
|
341 _crc = _crcTable[_idx] ^ (_crc >> 8); |
|
342 _idx = (_crc ^ cp[3]) & 0xFF; |
|
343 _crc = _crcTable[_idx] ^ (_crc >> 8); |
|
344 } |
|
345 while (n-- > 0) { |
|
346 unsigned char ch = *cp++; |
|
347 |
|
348 _crc = __builtin_ia32_crc32qi(_crc, ch); |
|
349 } |
|
350 |
|
351 if ((__POINTER_SIZE__==8) || (_crc <= _MAX_INT)) { |
|
352 __INST(crc) = __MKSMALLINT(_crc); |
|
353 } else { |
|
354 // this code fails with gcc 4.7.2: |
|
355 // __INST(crc) = __MKUINT(_crc); __STORESELF(crc); |
|
356 OBJ temp = __MKUINT(_crc); |
|
357 __INST(crc) = temp; __STORESELF(crc); |
|
358 } |
|
359 |
|
360 RETURN (count); |
|
361 } |
|
362 } |
|
363 bad: ; |
|
364 # endif |
|
365 #endif |
|
366 %}. |
|
367 self primitiveFailed |
|
368 |
|
369 "Created: / 17-03-2019 / 15:36:45 / Claus Gittinger" |
|
370 ! |
163 |
371 |
164 generatorPolynomMSB:anInteger |
372 generatorPolynomMSB:anInteger |
165 "notice, in literature, the generator polynom is usually specified as an MSB number" |
373 "notice, in literature, the generator polynom is usually specified as an MSB number" |
166 |
374 |
167 ^ self generatorPolynom:(anInteger bitReversed32) |
375 ^ self generatorPolynom:(anInteger bitReversed32) |
282 |
516 |
283 "Created: / 16-03-2019 / 21:06:16 / Claus Gittinger" |
517 "Created: / 16-03-2019 / 21:06:16 / Claus Gittinger" |
284 "Modified (format): / 17-03-2019 / 14:02:31 / Claus Gittinger" |
518 "Modified (format): / 17-03-2019 / 14:02:31 / Claus Gittinger" |
285 ! ! |
519 ! ! |
286 |
520 |
|
521 !CRC32Stream::CRC32Stream_Castagnoli class methodsFor:'documentation'! |
|
522 |
|
523 documentation |
|
524 " |
|
525 redefined to use the CPU's CRC instruction |
|
526 |
|
527 [author:] |
|
528 Claus Gittinger |
|
529 " |
|
530 ! ! |
|
531 |
|
532 !CRC32Stream::CRC32Stream_Castagnoli methodsFor:'writing'! |
|
533 |
|
534 nextPutBytes:count from:anObject startingAt:start |
|
535 "add the hash of anObject to the computed hash so far. |
|
536 This uses the x86/x86_64 crc instruction, |
|
537 and works only for the castagnoli polynom" |
|
538 |
|
539 %{ /* NOCONTEXT */ |
|
540 #if defined(__x86__) || defined(__x86_64__) |
|
541 # if defined(__clang__) || defined(__GNUC__) |
|
542 |
|
543 if (__bothSmallInteger(count, start)) { |
|
544 int len, offs; |
|
545 int objSize; |
|
546 unsigned char *extPtr; |
|
547 |
|
548 len = __intVal(count); |
|
549 offs = __intVal(start) - 1; |
|
550 |
|
551 if (__isExternalBytesLike(anObject)) { |
|
552 OBJ sz = __externalBytesSize(anObject); |
|
553 |
|
554 extPtr = (unsigned char *)__externalBytesAddress(anObject); |
|
555 if (__isSmallInteger(sz)) { |
|
556 objSize = __intVal(sz); |
|
557 } else { |
|
558 objSize = 0; /* unknown */ |
|
559 } |
|
560 } else { |
|
561 int nInstVars, nInstBytes; |
|
562 OBJ oClass = __Class(anObject); |
|
563 |
|
564 switch (__intVal(__ClassInstPtr(oClass)->c_flags) & ARRAYMASK) { |
|
565 case BYTEARRAY: |
|
566 case WORDARRAY: |
|
567 case LONGARRAY: |
|
568 case SWORDARRAY: |
|
569 case SLONGARRAY: |
|
570 case FLOATARRAY: |
|
571 case DOUBLEARRAY: |
|
572 break; |
|
573 default: |
|
574 goto bad; |
|
575 } |
|
576 nInstVars = __intVal(__ClassInstPtr(oClass)->c_ninstvars); |
|
577 nInstBytes = __OBJS2BYTES__(nInstVars); |
|
578 // nInstBytes is the number of bytes occupied by pointer instance variables |
|
579 // subtract from size and add to byte-pointer |
|
580 objSize = __qSize(anObject) - OHDR_SIZE - nInstBytes; |
|
581 extPtr = (unsigned char *)__byteArrayVal(anObject)+nInstBytes; |
|
582 } |
|
583 |
|
584 if ((offs >= 0) && (len >= 0) && (objSize >= (len + offs))) { |
|
585 unsigned int _crc; |
|
586 unsigned int *_crcTable = __integerArrayVal( __INST(crcTable) ); |
|
587 unsigned char *cp = extPtr+offs; |
|
588 unsigned int n = len; |
|
589 |
|
590 if (__isSmallInteger(__INST(crc))) { |
|
591 _crc = (unsigned int) (__intVal( __INST(crc) )); |
|
592 } else { |
|
593 _crc = __unsignedLongIntVal( __INST(crc) ); |
|
594 } |
|
595 |
|
596 # if __POINTER_SIZE__ == 8 |
|
597 if (((unsigned INT)cp & 7) == 0) { |
|
598 // longword aligned |
|
599 for ( ; n >= 32 ; n -= 32, cp += 32) { |
|
600 unsigned INT w0 = ((unsigned INT *)cp)[0]; |
|
601 unsigned INT w1, w2, w3; |
|
602 |
|
603 _crc = _mm_crc32_u64(_crc, w0); |
|
604 w1 = ((unsigned INT *)cp)[1]; |
|
605 _crc = _mm_crc32_u64(_crc, w1); |
|
606 w2 = ((unsigned INT *)cp)[2]; |
|
607 _crc = _mm_crc32_u64(_crc, w2); |
|
608 w3 = ((unsigned INT *)cp)[3]; |
|
609 _crc = _mm_crc32_u64(_crc, w3); |
|
610 } |
|
611 for ( ; n >= 8 ; n -= 8, cp += 8) { |
|
612 _crc = _mm_crc32_u64(_crc, ((unsigned INT *)cp)[0]); |
|
613 } |
|
614 } |
|
615 # endif // __POINTER_SIZE__ == 8 |
|
616 if (((unsigned INT)cp & 3) == 0) { |
|
617 // word aligned |
|
618 for ( ; n >= 4 ; n -= 4, cp += 4) { |
|
619 _crc = _mm_crc32_u32(_crc, ((unsigned int *)cp)[0]); |
|
620 } |
|
621 } |
|
622 for ( ; n >= 4 ; n -= 4, cp += 4) { |
|
623 _crc = _mm_crc32_u8(_crc, cp[0]); |
|
624 _crc = _mm_crc32_u8(_crc, cp[1]); |
|
625 _crc = _mm_crc32_u8(_crc, cp[2]); |
|
626 _crc = _mm_crc32_u8(_crc, cp[3]); |
|
627 } |
|
628 while (n-- > 0) { |
|
629 unsigned char ch = *cp++; |
|
630 |
|
631 _crc = _mm_crc32_u8(_crc, ch); |
|
632 } |
|
633 |
|
634 if ((__POINTER_SIZE__==8) || (_crc <= _MAX_INT)) { |
|
635 __INST(crc) = __MKSMALLINT(_crc); |
|
636 } else { |
|
637 // this code fails with gcc 4.7.2: |
|
638 // __INST(crc) = __MKUINT(_crc); __STORESELF(crc); |
|
639 OBJ temp = __MKUINT(_crc); |
|
640 __INST(crc) = temp; __STORESELF(crc); |
|
641 } |
|
642 |
|
643 RETURN (count); |
|
644 } |
|
645 } |
|
646 bad: ; |
|
647 # endif |
|
648 #endif |
|
649 %}. |
|
650 self primitiveFailed |
|
651 |
|
652 "Created: / 17-03-2019 / 16:44:27 / Claus Gittinger" |
|
653 ! ! |
|
654 |
287 !CRC32Stream class methodsFor:'documentation'! |
655 !CRC32Stream class methodsFor:'documentation'! |
288 |
656 |
289 version |
657 version |
290 ^ '$Header$' |
658 ^ '$Header$' |
291 ! |
659 ! |