Index: /trunk/src/VBox/Runtime/common/checksum/alt-sha1.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/checksum/alt-sha1.cpp	(revision 51877)
+++ /trunk/src/VBox/Runtime/common/checksum/alt-sha1.cpp	(revision 51878)
@@ -128,4 +128,33 @@
 
 
+/** Function 4.1, Ch(x,y,z). */
+DECL_FORCE_INLINE(uint32_t) rtSha1Ch(uint32_t uX, uint32_t uY, uint32_t uZ)
+{
+    uint32_t uResult = uX & uY;
+    uResult ^= ~uX & uZ;
+    return uResult;
+}
+
+
+/** Function 4.1, Parity(x,y,z). */
+DECL_FORCE_INLINE(uint32_t) rtSha1Parity(uint32_t uX, uint32_t uY, uint32_t uZ)
+{
+    uint32_t uResult = uX;
+    uResult ^= uY;
+    uResult ^= uZ;
+    return uResult;
+}
+
+
+/** Function 4.1, Maj(x,y,z). */
+DECL_FORCE_INLINE(uint32_t) rtSha1Maj(uint32_t uX, uint32_t uY, uint32_t uZ)
+{
+    uint32_t uResult = (uX & uY);
+    uResult |= (uX & uZ);
+    uResult |= (uY & uZ);
+    return uResult;
+}
+
+
 /**
  * Process the current block.
@@ -143,5 +172,41 @@
     uint32_t uE = pCtx->AltPrivate.auH[4];
 
-#if 1
+#if 1 /* Fully unrolled version. */
+    register uint32_t const *puW = &pCtx->AltPrivate.auW[0];
+# define SHA1_BODY(a_uW, a_uK, a_fnFt, a_uA, a_uB, a_uC, a_uD, a_uE) \
+        do { \
+            a_uE += a_uW; \
+            a_uE += (a_uK); \
+            a_uE += ASMRotateLeftU32(a_uA, 5); \
+            a_uE += a_fnFt(a_uB, a_uC, a_uD); \
+            a_uB = ASMRotateLeftU32(a_uB, 30); \
+        } while (0)
+# define FIVE_ITERATIONS(a_iStart, a_uK, a_fnFt) \
+    do { \
+        SHA1_BODY(/*puW[a_iStart + 0]*/ *puW++, a_uK, a_fnFt, uA, uB, uC, uD, uE); \
+        SHA1_BODY(/*puW[a_iStart + 1]*/ *puW++, a_uK, a_fnFt, uE, uA, uB, uC, uD); \
+        SHA1_BODY(/*puW[a_iStart + 2]*/ *puW++, a_uK, a_fnFt, uD, uE, uA, uB, uC); \
+        SHA1_BODY(/*puW[a_iStart + 3]*/ *puW++, a_uK, a_fnFt, uC, uD, uE, uA, uB); \
+        SHA1_BODY(/*puW[a_iStart + 4]*/ *puW++, a_uK, a_fnFt, uB, uC, uD, uE, uA); \
+    } while (0)
+# if 0 /* Variation that reduces the code size by a factor of 4 without much loss in preformance. */
+#  define TWENTY_ITERATIONS(a_iFirst, a_uK, a_fnFt) \
+    do { unsigned i = 4; while (i-- > 0) FIVE_ITERATIONS(a_iFirst + (3 - i) * 5, a_uK, a_fnFt); } while (0)
+    /*for (unsigned i = a_iFirst; i < (a_iFirst + 20); i += 5) FIVE_ITERATIONS(i, a_uK, a_fnFt);*/
+# else
+#  define TWENTY_ITERATIONS(a_iFirst, a_uK, a_fnFt) \
+    do { \
+        FIVE_ITERATIONS(a_iFirst +  0, a_uK, a_fnFt); \
+        FIVE_ITERATIONS(a_iFirst +  5, a_uK, a_fnFt); \
+        FIVE_ITERATIONS(a_iFirst + 10, a_uK, a_fnFt); \
+        FIVE_ITERATIONS(a_iFirst + 15, a_uK, a_fnFt); \
+    } while (0)
+# endif
+    TWENTY_ITERATIONS( 0, UINT32_C(0x5a827999), rtSha1Ch);
+    TWENTY_ITERATIONS(20, UINT32_C(0x6ed9eba1), rtSha1Parity);
+    TWENTY_ITERATIONS(40, UINT32_C(0x8f1bbcdc), rtSha1Maj);
+    TWENTY_ITERATIONS(60, UINT32_C(0xca62c1d6), rtSha1Parity);
+
+#elif 0 /* Version avoiding the constant selection. */
     unsigned iWord = 0;
 # define TWENTY_ITERATIONS(a_iWordStop, a_uK, a_uExprBCD) \
@@ -160,9 +225,10 @@
             uA = uTemp; \
         } do { } while (0)
-    TWENTY_ITERATIONS(20, UINT32_C(0x5a827999), (uB & uC) | (~uB & uD));
-    TWENTY_ITERATIONS(40, UINT32_C(0x6ed9eba1), uB ^ uC ^ uD);
-    TWENTY_ITERATIONS(60, UINT32_C(0x8f1bbcdc), (uB & uC) | (uB & uD) | (uC & uD));
-    TWENTY_ITERATIONS(80, UINT32_C(0xca62c1d6), uB ^ uC ^ uD);
-#else
+    TWENTY_ITERATIONS(20, UINT32_C(0x5a827999), rtSha1Ch(uB, uC, uD));
+    TWENTY_ITERATIONS(40, UINT32_C(0x6ed9eba1), rtSha1Parity(uB, uC, uD));
+    TWENTY_ITERATIONS(60, UINT32_C(0x8f1bbcdc), rtSha1Maj(uB, uC, uD));
+    TWENTY_ITERATIONS(80, UINT32_C(0xca62c1d6), rtSha1Parity(uB, uC, uD));
+
+#else /* Dead simple implementation. */
     for (unsigned iWord = 0; iWord < RT_ELEMENTS(pCtx->AltPrivate.auW); iWord++)
     {
Index: /trunk/src/VBox/Runtime/testcase/tstRTDigest-2.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstRTDigest-2.cpp	(revision 51877)
+++ /trunk/src/VBox/Runtime/testcase/tstRTDigest-2.cpp	(revision 51878)
@@ -36,4 +36,5 @@
 #include <iprt/err.h>
 #include <iprt/test.h>
+#include <iprt/thread.h>
 #include <iprt/string.h>
 
@@ -103,6 +104,8 @@
  * @param   cTests          The number of tests in the table.
  * @param   pszDigestName   The name of the digest.
+ * @param   enmDigestType   The digest enum type value.
  */
-static void testGeneric(const char *pszDigestObjId, TESTRTDIGEST const *paTests, size_t cTests, const char *pszDigestName)
+static void testGeneric(const char *pszDigestObjId, TESTRTDIGEST const *paTests, size_t cTests, const char *pszDigestName,
+                        RTDIGESTTYPE enmDigestType)
 {
     /*
@@ -154,32 +157,32 @@
      */
     RTTESTI_CHECK_RC_RETV(RTCrDigestCreateByObjIdString(&hDigest, pszDigestObjId), VINF_SUCCESS);
-    uint32_t cChunks  = 64;
+
+    /* Warmup. */
+    uint32_t cChunks  = enmDigestType == RTDIGESTTYPE_MD2 ? 12 : 128;
     uint32_t cLeft    = cChunks;
     int      rc       = VINF_SUCCESS;
-
+    RTThreadYield();
     uint64_t uStartTS = RTTimeNanoTS();
     while (cLeft-- > 0)
         rc |= RTCrDigestUpdate(hDigest, g_abRandom72KB, sizeof(g_abRandom72KB));
-    rc |= RTCrDigestFinal(hDigest, NULL, 0);
+    uint64_t cNsPerChunk = (RTTimeNanoTS() - uStartTS) / cChunks;
+    if (!cNsPerChunk)
+        cNsPerChunk = 16000000 / cChunks; /* Time resolution kludge: 16ms. */
+    RTTESTI_CHECK_RETV(rc == VINF_SUCCESS);
+
+    /* Do it for real for about 2 seconds. */
+    RTTESTI_CHECK_RC(RTCrDigestReset(hDigest), VINF_SUCCESS);
+    cChunks = _2G32 / cNsPerChunk;
+    cLeft   = cChunks;
+    RTThreadYield();
+    uStartTS = RTTimeNanoTS();
+    while (cLeft-- > 0)
+        rc |= RTCrDigestUpdate(hDigest, g_abRandom72KB, sizeof(g_abRandom72KB));
     uint64_t cNsElapsed = RTTimeNanoTS() - uStartTS;
     RTTESTI_CHECK(rc == VINF_SUCCESS);
 
-    /* If it was too quick, redo with more chunks. */
-    if (rc == VINF_SUCCESS && cNsElapsed < 100000000 /* 100 ms */)
-    {
-        cChunks  = 1024;
-        cLeft    = cChunks;
-        RTTESTI_CHECK_RC(RTCrDigestReset(hDigest), VINF_SUCCESS);
-
-        uStartTS = RTTimeNanoTS();
-        while (cLeft-- > 0)
-            rc |= RTCrDigestUpdate(hDigest, g_abRandom72KB, sizeof(g_abRandom72KB));
-        rc |= RTCrDigestFinal(hDigest, NULL, 0);
-        cNsElapsed = RTTimeNanoTS() - uStartTS;
-        RTTESTI_CHECK(rc == VINF_SUCCESS);
-    }
-
     RTTestIValueF((uint64_t)cChunks * sizeof(g_abRandom72KB) / _1K / (0.000000001 * cNsElapsed), RTTESTUNIT_KILOBYTES_PER_SEC,
                   "%s throughput", pszDigestName);
+    RTTESTI_CHECK_RC(RTCrDigestRelease(hDigest), 0);
 }
 
@@ -380,5 +383,5 @@
         { &g_abRandom72KB[0x20c9],  9991, "bbba194efa81238e5b613e20e937144e", "MD2 8393 bytes @9991" },
     };
-    testGeneric("1.2.840.113549.2.2", s_abTests, RT_ELEMENTS(s_abTests), "MD2");
+    testGeneric("1.2.840.113549.2.2", s_abTests, RT_ELEMENTS(s_abTests), "MD2", RTDIGESTTYPE_MD2);
 }
 
@@ -579,5 +582,5 @@
         { &g_abRandom72KB[0x20c9], 9991, "6461339c6615d23c704298a313e07cf5", "MD5 8393 bytes @9991" },
     };
-    testGeneric("1.2.840.113549.2.5", s_abTests, RT_ELEMENTS(s_abTests), "MD5");
+    testGeneric("1.2.840.113549.2.5", s_abTests, RT_ELEMENTS(s_abTests), "MD5", RTDIGESTTYPE_MD5);
 }
 
@@ -758,5 +761,5 @@
         { &g_abRandom72KB[0x20c9],  9991, "62001184bacacce3774566d916055d425a85eba5", "SHA-1 8393 bytes @9991" },
     };
-    testGeneric("1.3.14.3.2.26", s_abTests, RT_ELEMENTS(s_abTests), "SHA-1");
+    testGeneric("1.3.14.3.2.26", s_abTests, RT_ELEMENTS(s_abTests), "SHA-1", RTDIGESTTYPE_SHA1);
 }
 
@@ -926,5 +929,5 @@
         { &g_abRandom72KB[0x20c9],  9991, "8bd4c6142e36f15385769ebdeb855dcdf542f72d067315472a52ff626946310e", "SHA-256 8393 bytes @9991" },
     };
-    testGeneric("2.16.840.1.101.3.4.2.1", s_abTests, RT_ELEMENTS(s_abTests), "SHA-256");
+    testGeneric("2.16.840.1.101.3.4.2.1", s_abTests, RT_ELEMENTS(s_abTests), "SHA-256", RTDIGESTTYPE_SHA256);
 }
 
@@ -964,5 +967,5 @@
           "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525", "SHA-224 abcdbc..." },
     };
-    testGeneric("2.16.840.1.101.3.4.2.4", s_abTests, RT_ELEMENTS(s_abTests), "SHA-224");
+    testGeneric("2.16.840.1.101.3.4.2.4", s_abTests, RT_ELEMENTS(s_abTests), "SHA-224", RTDIGESTTYPE_SHA224);
 }
 
@@ -1132,5 +1135,5 @@
         { &g_abRandom72KB[0x20c9],  9991, "d6ac7c68664df2e34dc6be233b33f8dad196348350b70a4c2c5a78eb54d6e297c819771313d798de7552b7a3cb85370aab25087e189f3be8560d49406ebb6280", "SHA-512 8393 bytes @9991" },
     };
-    testGeneric("2.16.840.1.101.3.4.2.3", s_abTests, RT_ELEMENTS(s_abTests), "SHA-512");
+    testGeneric("2.16.840.1.101.3.4.2.3", s_abTests, RT_ELEMENTS(s_abTests), "SHA-512", RTDIGESTTYPE_SHA512);
 }
 
@@ -1170,5 +1173,5 @@
           "23fec5bb94d60b23308192640b0c453335d664734fe40e7268674af9", "SHA-512/256 abcdef..." },
     };
-    testGeneric("2.16.840.1.101.3.4.2.5", s_abTests, RT_ELEMENTS(s_abTests), "SHA-512/224");
+    testGeneric("2.16.840.1.101.3.4.2.5", s_abTests, RT_ELEMENTS(s_abTests), "SHA-512/224", RTDIGESTTYPE_SHA512T224);
 }
 #endif /* IPRT_WITHOUT_SHA512T224 */
@@ -1208,5 +1211,5 @@
           "3928e184fb8690f840da3988121d31be65cb9d3ef83ee6146feac861e19b563a", "SHA-512/256 abcdef..." },
     };
-    testGeneric("2.16.840.1.101.3.4.2.6", s_abTests, RT_ELEMENTS(s_abTests), "SHA-512/256");
+    testGeneric("2.16.840.1.101.3.4.2.6", s_abTests, RT_ELEMENTS(s_abTests), "SHA-512/256", RTDIGESTTYPE_SHA512T256);
 }
 #endif /* !IPRT_WITHOUT_SHA512T256 */
@@ -1245,5 +1248,5 @@
           "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039", "SHA-384 abcdef..." },
     };
-    testGeneric("2.16.840.1.101.3.4.2.2", s_abTests, RT_ELEMENTS(s_abTests), "SHA-384");
+    testGeneric("2.16.840.1.101.3.4.2.2", s_abTests, RT_ELEMENTS(s_abTests), "SHA-384", RTDIGESTTYPE_SHA384);
 }
 
