diff -r 65bb2eee0144 -r 22c01d2b1186 SHA1Stream.st --- a/SHA1Stream.st Sat Mar 23 15:18:05 2019 +0100 +++ b/SHA1Stream.st Sat Mar 23 15:30:15 2019 +0100 @@ -51,11 +51,22 @@ #if defined(__GNUC__) || defined(__CLANG__) # define STATIC_INLINE static inline +# define __SSE4_1__ +# define __SHA__ +# include + static void SHA1Transform(unsigned int32 state[5], unsigned char buffer[64]); + // static void __attribute__ ((__target__ ("sha,sse4.1"))) SHA1Transform_x86(unsigned int32 state[5], unsigned char buffer[64]); + static void SHA1Transform_x86(unsigned int32 state[5], unsigned char buffer[64]); +# define USE_SHA_INTRINSICS +#endif + +#ifndef USE_SHA_INTRINSICS +# define SHA1Transform SHA1Transform_generic #endif #if USE_ANSI_C - void SHA1Transform(unsigned int32 /* long */ state[5], unsigned char buffer[64]); + static void SHA1Transform_generic(unsigned int32 state[5], unsigned char buffer[64]); STATIC_INLINE void SHA1Init(SHA1_CTX* context); void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len); void SHA1Final(unsigned char digest[20], SHA1_CTX* context); @@ -76,7 +87,6 @@ ! ! !SHA1Stream primitiveFunctions! - %{ /* @@ -111,9 +121,9 @@ */ static void #if USE_ANSI_C -SHA1Transform (unsigned int32 state[5], unsigned char buffer[64]) +SHA1Transform_generic (unsigned int32 state[5], unsigned char buffer[64]) #else -SHA1Transform (state, buffer) +SHA1Transform_generic (state, buffer) unsigned int32 state[5]; unsigned char buffer[64]; #endif @@ -168,6 +178,221 @@ a = b = c = d = e = 0; } +#if defined(__CLANG__) + +static void +SHA1Transform_x86 (unsigned int32 state[5], unsigned char buffer[64]) +{ + unsigned int32 a, b, c, d, e; + typedef union { + unsigned char c[64]; + unsigned int32 /* long */ l[16]; + } CHAR64LONG16; + CHAR64LONG16* block; +#ifdef SHA1HANDSOFF + static unsigned char workspace[64]; + block = (CHAR64LONG16*)workspace; + memcpy(block, buffer, 64); +#else + block = (CHAR64LONG16*)buffer; +#endif + __m128i ABCD, ABCD_SAVE, E0, E0_SAVE, E1; + __m128i MSG0, MSG1, MSG2, MSG3; + const __m128i MASK = _mm_set_epi64x(0x0001020304050607ULL, 0x08090a0b0c0d0e0fULL); + + /* Load initial values */ + ABCD = _mm_loadu_si128((const __m128i*) state); + E0 = _mm_set_epi32(state[4], 0, 0, 0); + ABCD = _mm_shuffle_epi32(ABCD, 0x1B); + + /* Save current state */ + ABCD_SAVE = ABCD; + E0_SAVE = E0; + + /* Rounds 0-3 */ + MSG0 = _mm_loadu_si128((const __m128i*)(block + 0)); + MSG0 = _mm_shuffle_epi8(MSG0, MASK); + E0 = _mm_add_epi32(E0, MSG0); + E1 = ABCD; + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 0); + + /* Rounds 4-7 */ + MSG1 = _mm_loadu_si128((const __m128i*)(block + 16)); + MSG1 = _mm_shuffle_epi8(MSG1, MASK); + E1 = _mm_sha1nexte_epu32(E1, MSG1); + E0 = ABCD; + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 0); + MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1); + + /* Rounds 8-11 */ + MSG2 = _mm_loadu_si128((const __m128i*)(block + 32)); + MSG2 = _mm_shuffle_epi8(MSG2, MASK); + E0 = _mm_sha1nexte_epu32(E0, MSG2); + E1 = ABCD; + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 0); + MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2); + MSG0 = _mm_xor_si128(MSG0, MSG2); + + /* Rounds 12-15 */ + MSG3 = _mm_loadu_si128((const __m128i*)(block + 48)); + MSG3 = _mm_shuffle_epi8(MSG3, MASK); + E1 = _mm_sha1nexte_epu32(E1, MSG3); + E0 = ABCD; + MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 0); + MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3); + MSG1 = _mm_xor_si128(MSG1, MSG3); + + /* Rounds 16-19 */ + E0 = _mm_sha1nexte_epu32(E0, MSG0); + E1 = ABCD; + MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 0); + MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0); + MSG2 = _mm_xor_si128(MSG2, MSG0); + + /* Rounds 20-23 */ + E1 = _mm_sha1nexte_epu32(E1, MSG1); + E0 = ABCD; + MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 1); + MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1); + MSG3 = _mm_xor_si128(MSG3, MSG1); + + /* Rounds 24-27 */ + E0 = _mm_sha1nexte_epu32(E0, MSG2); + E1 = ABCD; + MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 1); + MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2); + MSG0 = _mm_xor_si128(MSG0, MSG2); + + /* Rounds 28-31 */ + E1 = _mm_sha1nexte_epu32(E1, MSG3); + E0 = ABCD; + MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 1); + MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3); + MSG1 = _mm_xor_si128(MSG1, MSG3); + + /* Rounds 32-35 */ + E0 = _mm_sha1nexte_epu32(E0, MSG0); + E1 = ABCD; + MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 1); + MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0); + MSG2 = _mm_xor_si128(MSG2, MSG0); + + /* Rounds 36-39 */ + E1 = _mm_sha1nexte_epu32(E1, MSG1); + E0 = ABCD; + MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 1); + MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1); + MSG3 = _mm_xor_si128(MSG3, MSG1); + + /* Rounds 40-43 */ + E0 = _mm_sha1nexte_epu32(E0, MSG2); + E1 = ABCD; + MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 2); + MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2); + MSG0 = _mm_xor_si128(MSG0, MSG2); + + /* Rounds 44-47 */ + E1 = _mm_sha1nexte_epu32(E1, MSG3); + E0 = ABCD; + MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 2); + MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3); + MSG1 = _mm_xor_si128(MSG1, MSG3); + + /* Rounds 48-51 */ + E0 = _mm_sha1nexte_epu32(E0, MSG0); + E1 = ABCD; + MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 2); + MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0); + MSG2 = _mm_xor_si128(MSG2, MSG0); + + /* Rounds 52-55 */ + E1 = _mm_sha1nexte_epu32(E1, MSG1); + E0 = ABCD; + MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 2); + MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1); + MSG3 = _mm_xor_si128(MSG3, MSG1); + + /* Rounds 56-59 */ + E0 = _mm_sha1nexte_epu32(E0, MSG2); + E1 = ABCD; + MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 2); + MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2); + MSG0 = _mm_xor_si128(MSG0, MSG2); + + /* Rounds 60-63 */ + E1 = _mm_sha1nexte_epu32(E1, MSG3); + E0 = ABCD; + MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 3); + MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3); + MSG1 = _mm_xor_si128(MSG1, MSG3); + + /* Rounds 64-67 */ + E0 = _mm_sha1nexte_epu32(E0, MSG0); + E1 = ABCD; + MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 3); + MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0); + MSG2 = _mm_xor_si128(MSG2, MSG0); + + /* Rounds 68-71 */ + E1 = _mm_sha1nexte_epu32(E1, MSG1); + E0 = ABCD; + MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 3); + MSG3 = _mm_xor_si128(MSG3, MSG1); + + /* Rounds 72-75 */ + E0 = _mm_sha1nexte_epu32(E0, MSG2); + E1 = ABCD; + MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 3); + + /* Rounds 76-79 */ + E1 = _mm_sha1nexte_epu32(E1, MSG3); + E0 = ABCD; + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 3); + + /* Combine state */ + E0 = _mm_sha1nexte_epu32(E0, E0_SAVE); + ABCD = _mm_add_epi32(ABCD, ABCD_SAVE); + + /* Save state */ + ABCD = _mm_shuffle_epi32(ABCD, 0x1B); + _mm_storeu_si128((__m128i*) state, ABCD); + state[4] = _mm_extract_epi32(E0, 3); +} + +#endif + +#ifdef USE_SHA_INTRINSICS + +static void +#if USE_ANSI_C +SHA1Transform(unsigned int32 state[5], unsigned char buffer[64]) +#else +SHA1Transform(state, buffer) + unsigned int32 state[5]; + unsigned char buffer[64]; +#endif +{ + SHA1Transform_generic(state, buffer); +} + +#endif + /* * SHA1Init - Initialize new context */ @@ -240,7 +465,7 @@ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ } SHA1Update(context, (unsigned char *)"\200", 1); - while ((context->count[0] & 504) != 448) { + while ((context->count[0] & 504 /* 16r1F8 */) != 448 /* 16r1C0 */) { SHA1Update(context, (unsigned char *)"\0", 1); } SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ @@ -444,27 +669,31 @@ CPU cc algo mb/sec MAC (2010 macbook; 2.7Ghz Duo) clang -O2 slow 128.5 - 132 - MAC (2012 macbook; 2.6Ghz I7) clang -O2 203.5 + 132 + MAC (2012 macbook; 2.6Ghz I7) clang -O2 190 + chunk size 10: 86.70 Mb/s + chunk size 50: 227.07 Mb/s + chunk size 1000: 405.82 Mb/s + chunk size 50000: 421.98 Mb/s timing throughput: - [exBegin] + [exBegin] |hashStream n t| hashStream := SHA1Stream new. n := 1000000. t := Time millisecondsToRun:[ - n timesRepeat:[ - hashStream nextPutAll:'12345678901234567890123456789012345678901234567890'. - ]. - ]. + n timesRepeat:[ + hashStream nextPutAll:'12345678901234567890123456789012345678901234567890'. + ]. + ]. t := (t / 1000) asFloat. Transcript show:t; show:' seconds for '; show:(50*n/1024) asFloat; showCR:' Kb'. Transcript show:(n*50/1024 / t); showCR:' Kb/s' - [exEnd] + [exEnd] " ! ! @@ -609,20 +838,26 @@ "update the hash value with anInteger <= 255." %{ - if (__isSmallInteger(anInteger) && __intVal(anInteger) <= 255 - && __isByteArray(__INST(hashContext)) - && __byteArraySize(__INST(hashContext)) == sizeof(SHA1_CTX) + unsigned char value; + OBJ _hashContext = __INST(hashContext); + + // fetch first; check below + value = __intVal(anInteger); + if (__isSmallInteger(anInteger) && value <= 255 + && __isByteArray(_hashContext) + && __byteArraySize(_hashContext) == sizeof(SHA1_CTX) ) { - SHA1_CTX *ctx = (SHA1_CTX *)__ByteArrayInstPtr(__INST(hashContext))->ba_element; - unsigned char value = __intVal(anInteger); + SHA1_CTX *ctx = (SHA1_CTX *)__byteArrayVal(_hashContext); - SHA1Update(ctx, &value, 1); - RETURN(self); + SHA1Update(ctx, &value, 1); + RETURN(self); } bad: ; %}. ^ self primitiveFailed + + "Modified: / 23-03-2019 / 15:19:40 / Claus Gittinger" ! nextPutBytes:count from:anObject startingAt:start @@ -636,69 +871,78 @@ INT objSize; int nInstBytes; char *extPtr; + OBJ _hashContext = __INST(hashContext); - if (__isByteArray(__INST(hashContext)) - && __byteArraySize(__INST(hashContext)) == sizeof(SHA1_CTX) + // convert here; check later + len = __intVal(count); + offs = __intVal(start) - 1; + + if (__isByteArray(_hashContext) + && __byteArraySize(_hashContext) == sizeof(SHA1_CTX) && __bothSmallInteger(count, start) - ) { - SHA1_CTX *ctx = (SHA1_CTX *)__ByteArrayInstPtr(__INST(hashContext))->ba_element; - - len = __intVal(count); - offs = __intVal(start) - 1; - - if (__isExternalBytesLike(anObject)) { - OBJ sz; + ) { + SHA1_CTX *ctx = (SHA1_CTX *)__byteArrayVal(_hashContext); - nInstBytes = 0; - extPtr = (char *)__externalBytesAddress(anObject); - if (extPtr == NULL) goto bad; - sz = __externalBytesSize(anObject); - if (__isSmallInteger(sz)) { - objSize = __intVal(sz); - } else { - objSize = 0; /* unknown */ - } - } else { - OBJ oClass = __Class(anObject); - int nInstVars = __intVal(__ClassInstPtr(oClass)->c_ninstvars); + if (__isByteArrayLike(anObject)) { + extPtr = (char *)__byteArrayVal(anObject); + objSize = __byteArraySize(anObject); + } else if (__isStringLike(anObject)) { + extPtr = (char *)__stringVal(anObject); + objSize = __stringSize(anObject); + } else if (__isExternalBytesLike(anObject)) { + OBJ sz; + + nInstBytes = 0; + extPtr = (char *)__externalBytesAddress(anObject); + if (extPtr == NULL) goto bad; + sz = __externalBytesSize(anObject); + objSize = __intVal(sz); + if (!__isSmallInteger(sz)) { + objSize = 0; /* unknown */ + } + } else { + OBJ oClass = __Class(anObject); + int nInstVars = __intVal(__ClassInstPtr(oClass)->c_ninstvars); - nInstBytes = OHDR_SIZE + __OBJS2BYTES__(nInstVars); - switch (__intVal(__ClassInstPtr(oClass)->c_flags) & ARRAYMASK) { - case BYTEARRAY: - case WORDARRAY: - case LONGARRAY: - case SWORDARRAY: - case SLONGARRAY: - case FLOATARRAY: - break; - case DOUBLEARRAY: + nInstBytes = OHDR_SIZE + __OBJS2BYTES__(nInstVars); + switch (__intVal(__ClassInstPtr(oClass)->c_flags) & ARRAYMASK) { + case BYTEARRAY: + case WORDARRAY: + case LONGARRAY: + case SWORDARRAY: + case SLONGARRAY: + case FLOATARRAY: + break; + case DOUBLEARRAY: #ifdef __NEED_DOUBLE_ALIGN - nInstBytes = (nInstBytes-1+__DOUBLE_ALIGN) &~ (__DOUBLE_ALIGN-1); + nInstBytes = (nInstBytes-1+__DOUBLE_ALIGN) &~ (__DOUBLE_ALIGN-1); #endif - break; - case LONGLONGARRAY: - case SLONGLONGARRAY: + break; + case LONGLONGARRAY: + case SLONGLONGARRAY: #ifdef __NEED_LONGLONG_ALIGN - nInstBytes = (nInstBytes-1+__LONGLONG_ALIGN) &~ (__LONGLONG_ALIGN-1); + nInstBytes = (nInstBytes-1+__LONGLONG_ALIGN) &~ (__LONGLONG_ALIGN-1); #endif - break; - default: - goto bad; - } - // nInstBytes is the number of bytes occupied by pointer instance variables - // subtract from size and add to byte-pointer - objSize = __Size(anObject) - nInstBytes; - extPtr = (char *)anObject + nInstBytes; - } - if ((offs >= 0) && (len >= 0) && (objSize >= (len + offs))) { - SHA1Update(ctx, extPtr+offs, (unsigned int)len); - RETURN (count); - } + break; + default: + goto bad; + } + // nInstBytes is the number of bytes occupied by pointer instance variables + // subtract from size and add to byte-pointer + objSize = __Size(anObject) - nInstBytes; + extPtr = (char *)anObject + nInstBytes; + } + if ((offs >= 0) && (len >= 0) && (objSize >= (len + offs))) { + SHA1Update(ctx, extPtr+offs, (unsigned int)len); + RETURN (count); + } } bad: ; %}. ^ self primitiveFailed + + "Modified: / 23-03-2019 / 15:28:31 / Claus Gittinger" ! ! !SHA1Stream class methodsFor:'documentation'!