From 1449e239c2e2eb00e911c1b241f5492805f17934 Mon Sep 17 00:00:00 2001
From: Jens Steube <jens.steube@gmail.com>
Date: Thu, 20 Feb 2020 11:01:56 +0100
Subject: [PATCH] Optimize some -m 780x code in kernels

---
 OpenCL/m07800_a0-optimized.cl | 124 ++++++++++++++++++----------------
 OpenCL/m07800_a1-optimized.cl | 124 ++++++++++++++++++----------------
 OpenCL/m07800_a3-optimized.cl | 124 ++++++++++++++++++----------------
 OpenCL/m07801_a0-optimized.cl | 124 ++++++++++++++++++----------------
 OpenCL/m07801_a1-optimized.cl | 124 ++++++++++++++++++----------------
 OpenCL/m07801_a3-optimized.cl | 124 ++++++++++++++++++----------------
 6 files changed, 396 insertions(+), 348 deletions(-)

diff --git a/OpenCL/m07800_a0-optimized.cl b/OpenCL/m07800_a0-optimized.cl
index 4d86b2858..7dab142cb 100644
--- a/OpenCL/m07800_a0-optimized.cl
+++ b/OpenCL/m07800_a0-optimized.cl
@@ -191,33 +191,33 @@ KERNEL_FQ void m07800_m04 (KERN_ATTR_RULES ())
     digest[3] = SHA1M_D;
     digest[4] = SHA1M_E;
 
-    sha1_transform (&final[0], &final[4], &final[8], &final[12], digest);
+    sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
 
     // prepare magic array range
 
     u32 lengthMagicArray = 0x20;
     u32 offsetMagicArray = 0;
 
-    lengthMagicArray += ((digest[0] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >> 16) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >>  8) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >>  0) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >> 16) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >>  8) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >>  0) & 0xff) % 6;
-    lengthMagicArray += ((digest[2] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[2] >> 16) & 0xff) % 6;
-    offsetMagicArray += ((digest[2] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[2] >>  0) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >> 24) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >> 16) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >>  0) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >> 24) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >> 16) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >>  0) & 0xff) % 8;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8b_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8a_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8b_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8a_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[2]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[2]) % 6;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[2]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[2]) & 7;
+    offsetMagicArray += unpack_v8d_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8c_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8d_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8c_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[4]) & 7;
 
     // final
 
@@ -278,17 +278,21 @@ KERNEL_FQ void m07800_m04 (KERN_ATTR_RULES ())
 
     // calculate
 
-    int left;
-    int off;
-
-    for (left = final_len, off = 0; left >= 56; left -= 64, off += 16)
+    if (final_len >= 56)
     {
-      sha1_transform (&final[off + 0], &final[off + 4], &final[off + 8], &final[off + 12], digest);
+      final[30] = 0;
+      final[31] = final_len * 8;
+
+      sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
+      sha1_transform (final + 16, final + 20, final + 24, final + 28, digest);
     }
+    else
+    {
+      final[14] = 0;
+      final[15] = final_len * 8;
 
-    final[off + 15] = final_len * 8;
-
-    sha1_transform (&final[off + 0], &final[off + 4], &final[off + 8], &final[off + 12], digest);
+      sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
+    }
 
     COMPARE_M_SIMD (digest[3], digest[4], digest[2], digest[1]);
   }
@@ -451,33 +455,33 @@ KERNEL_FQ void m07800_s04 (KERN_ATTR_RULES ())
     digest[3] = SHA1M_D;
     digest[4] = SHA1M_E;
 
-    sha1_transform (&final[0], &final[4], &final[8], &final[12], digest);
+    sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
 
     // prepare magic array range
 
     u32 lengthMagicArray = 0x20;
     u32 offsetMagicArray = 0;
 
-    lengthMagicArray += ((digest[0] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >> 16) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >>  8) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >>  0) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >> 16) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >>  8) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >>  0) & 0xff) % 6;
-    lengthMagicArray += ((digest[2] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[2] >> 16) & 0xff) % 6;
-    offsetMagicArray += ((digest[2] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[2] >>  0) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >> 24) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >> 16) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >>  0) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >> 24) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >> 16) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >>  0) & 0xff) % 8;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8b_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8a_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8b_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8a_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[2]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[2]) % 6;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[2]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[2]) & 7;
+    offsetMagicArray += unpack_v8d_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8c_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8d_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8c_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[4]) & 7;
 
     // final
 
@@ -538,17 +542,21 @@ KERNEL_FQ void m07800_s04 (KERN_ATTR_RULES ())
 
     // calculate
 
-    int left;
-    int off;
-
-    for (left = final_len, off = 0; left >= 56; left -= 64, off += 16)
+    if (final_len >= 56)
     {
-      sha1_transform (&final[off + 0], &final[off + 4], &final[off + 8], &final[off + 12], digest);
+      final[30] = 0;
+      final[31] = final_len * 8;
+
+      sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
+      sha1_transform (final + 16, final + 20, final + 24, final + 28, digest);
     }
+    else
+    {
+      final[14] = 0;
+      final[15] = final_len * 8;
 
-    final[off + 15] = final_len * 8;
-
-    sha1_transform (&final[off + 0], &final[off + 4], &final[off + 8], &final[off + 12], digest);
+      sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
+    }
 
     COMPARE_S_SIMD (digest[3], digest[4], digest[2], digest[1]);
   }
diff --git a/OpenCL/m07800_a1-optimized.cl b/OpenCL/m07800_a1-optimized.cl
index cc552143f..0ce766c16 100644
--- a/OpenCL/m07800_a1-optimized.cl
+++ b/OpenCL/m07800_a1-optimized.cl
@@ -249,33 +249,33 @@ KERNEL_FQ void m07800_m04 (KERN_ATTR_BASIC ())
     digest[3] = SHA1M_D;
     digest[4] = SHA1M_E;
 
-    sha1_transform (&final[0], &final[4], &final[8], &final[12], digest);
+    sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
 
     // prepare magic array range
 
     u32 lengthMagicArray = 0x20;
     u32 offsetMagicArray = 0;
 
-    lengthMagicArray += ((digest[0] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >> 16) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >>  8) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >>  0) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >> 16) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >>  8) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >>  0) & 0xff) % 6;
-    lengthMagicArray += ((digest[2] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[2] >> 16) & 0xff) % 6;
-    offsetMagicArray += ((digest[2] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[2] >>  0) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >> 24) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >> 16) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >>  0) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >> 24) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >> 16) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >>  0) & 0xff) % 8;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8b_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8a_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8b_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8a_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[2]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[2]) % 6;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[2]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[2]) & 7;
+    offsetMagicArray += unpack_v8d_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8c_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8d_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8c_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[4]) & 7;
 
     // final
 
@@ -336,17 +336,21 @@ KERNEL_FQ void m07800_m04 (KERN_ATTR_BASIC ())
 
     // calculate
 
-    int left;
-    int off;
-
-    for (left = final_len, off = 0; left >= 56; left -= 64, off += 16)
+    if (final_len >= 56)
     {
-      sha1_transform (&final[off + 0], &final[off + 4], &final[off + 8], &final[off + 12], digest);
+      final[30] = 0;
+      final[31] = final_len * 8;
+
+      sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
+      sha1_transform (final + 16, final + 20, final + 24, final + 28, digest);
     }
+    else
+    {
+      final[14] = 0;
+      final[15] = final_len * 8;
 
-    final[off + 15] = final_len * 8;
-
-    sha1_transform (&final[off + 0], &final[off + 4], &final[off + 8], &final[off + 12], digest);
+      sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
+    }
 
     COMPARE_M_SIMD (digest[3], digest[4], digest[2], digest[1]);
   }
@@ -569,33 +573,33 @@ KERNEL_FQ void m07800_s04 (KERN_ATTR_BASIC ())
     digest[3] = SHA1M_D;
     digest[4] = SHA1M_E;
 
-    sha1_transform (&final[0], &final[4], &final[8], &final[12], digest);
+    sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
 
     // prepare magic array range
 
     u32 lengthMagicArray = 0x20;
     u32 offsetMagicArray = 0;
 
-    lengthMagicArray += ((digest[0] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >> 16) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >>  8) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >>  0) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >> 16) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >>  8) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >>  0) & 0xff) % 6;
-    lengthMagicArray += ((digest[2] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[2] >> 16) & 0xff) % 6;
-    offsetMagicArray += ((digest[2] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[2] >>  0) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >> 24) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >> 16) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >>  0) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >> 24) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >> 16) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >>  0) & 0xff) % 8;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8b_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8a_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8b_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8a_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[2]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[2]) % 6;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[2]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[2]) & 7;
+    offsetMagicArray += unpack_v8d_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8c_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8d_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8c_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[4]) & 7;
 
     // final
 
@@ -656,17 +660,21 @@ KERNEL_FQ void m07800_s04 (KERN_ATTR_BASIC ())
 
     // calculate
 
-    int left;
-    int off;
-
-    for (left = final_len, off = 0; left >= 56; left -= 64, off += 16)
+    if (final_len >= 56)
     {
-      sha1_transform (&final[off + 0], &final[off + 4], &final[off + 8], &final[off + 12], digest);
+      final[30] = 0;
+      final[31] = final_len * 8;
+
+      sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
+      sha1_transform (final + 16, final + 20, final + 24, final + 28, digest);
     }
+    else
+    {
+      final[14] = 0;
+      final[15] = final_len * 8;
 
-    final[off + 15] = final_len * 8;
-
-    sha1_transform (&final[off + 0], &final[off + 4], &final[off + 8], &final[off + 12], digest);
+      sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
+    }
 
     COMPARE_S_SIMD (digest[3], digest[4], digest[2], digest[1]);
   }
diff --git a/OpenCL/m07800_a3-optimized.cl b/OpenCL/m07800_a3-optimized.cl
index de22475f0..4ee34d3dc 100644
--- a/OpenCL/m07800_a3-optimized.cl
+++ b/OpenCL/m07800_a3-optimized.cl
@@ -165,33 +165,33 @@ DECLSPEC void m07800m (u32 *w0, u32 *w1, u32 *w2, u32 *w3, const u32 pw_len, KER
     digest[3] = SHA1M_D;
     digest[4] = SHA1M_E;
 
-    sha1_transform (&final[0], &final[4], &final[8], &final[12], digest);
+    sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
 
     // prepare magic array range
 
     u32 lengthMagicArray = 0x20;
     u32 offsetMagicArray = 0;
 
-    lengthMagicArray += ((digest[0] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >> 16) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >>  8) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >>  0) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >> 16) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >>  8) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >>  0) & 0xff) % 6;
-    lengthMagicArray += ((digest[2] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[2] >> 16) & 0xff) % 6;
-    offsetMagicArray += ((digest[2] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[2] >>  0) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >> 24) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >> 16) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >>  0) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >> 24) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >> 16) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >>  0) & 0xff) % 8;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8b_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8a_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8b_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8a_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[2]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[2]) % 6;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[2]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[2]) & 7;
+    offsetMagicArray += unpack_v8d_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8c_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8d_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8c_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[4]) & 7;
 
     // final
 
@@ -252,17 +252,21 @@ DECLSPEC void m07800m (u32 *w0, u32 *w1, u32 *w2, u32 *w3, const u32 pw_len, KER
 
     // calculate
 
-    int left;
-    int off;
-
-    for (left = final_len, off = 0; left >= 56; left -= 64, off += 16)
+    if (final_len >= 56)
     {
-      sha1_transform (&final[off + 0], &final[off + 4], &final[off + 8], &final[off + 12], digest);
+      final[30] = 0;
+      final[31] = final_len * 8;
+
+      sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
+      sha1_transform (final + 16, final + 20, final + 24, final + 28, digest);
     }
+    else
+    {
+      final[14] = 0;
+      final[15] = final_len * 8;
 
-    final[off + 15] = final_len * 8;
-
-    sha1_transform (&final[off + 0], &final[off + 4], &final[off + 8], &final[off + 12], digest);
+      sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
+    }
 
     COMPARE_M_SIMD (digest[3], digest[4], digest[2], digest[1]);
   }
@@ -393,33 +397,33 @@ DECLSPEC void m07800s (u32 *w0, u32 *w1, u32 *w2, u32 *w3, const u32 pw_len, KER
     digest[3] = SHA1M_D;
     digest[4] = SHA1M_E;
 
-    sha1_transform (&final[0], &final[4], &final[8], &final[12], digest);
+    sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
 
     // prepare magic array range
 
     u32 lengthMagicArray = 0x20;
     u32 offsetMagicArray = 0;
 
-    lengthMagicArray += ((digest[0] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >> 16) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >>  8) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >>  0) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >> 16) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >>  8) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >>  0) & 0xff) % 6;
-    lengthMagicArray += ((digest[2] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[2] >> 16) & 0xff) % 6;
-    offsetMagicArray += ((digest[2] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[2] >>  0) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >> 24) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >> 16) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >>  0) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >> 24) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >> 16) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >>  0) & 0xff) % 8;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8b_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8a_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8b_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8a_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[2]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[2]) % 6;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[2]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[2]) & 7;
+    offsetMagicArray += unpack_v8d_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8c_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8d_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8c_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[4]) & 7;
 
     // final
 
@@ -480,17 +484,21 @@ DECLSPEC void m07800s (u32 *w0, u32 *w1, u32 *w2, u32 *w3, const u32 pw_len, KER
 
     // calculate
 
-    int left;
-    int off;
-
-    for (left = final_len, off = 0; left >= 56; left -= 64, off += 16)
+    if (final_len >= 56)
     {
-      sha1_transform (&final[off + 0], &final[off + 4], &final[off + 8], &final[off + 12], digest);
+      final[30] = 0;
+      final[31] = final_len * 8;
+
+      sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
+      sha1_transform (final + 16, final + 20, final + 24, final + 28, digest);
     }
+    else
+    {
+      final[14] = 0;
+      final[15] = final_len * 8;
 
-    final[off + 15] = final_len * 8;
-
-    sha1_transform (&final[off + 0], &final[off + 4], &final[off + 8], &final[off + 12], digest);
+      sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
+    }
 
     COMPARE_S_SIMD (digest[3], digest[4], digest[2], digest[1]);
   }
diff --git a/OpenCL/m07801_a0-optimized.cl b/OpenCL/m07801_a0-optimized.cl
index aeb9b95d0..13059adfe 100644
--- a/OpenCL/m07801_a0-optimized.cl
+++ b/OpenCL/m07801_a0-optimized.cl
@@ -191,33 +191,33 @@ KERNEL_FQ void m07801_m04 (KERN_ATTR_RULES ())
     digest[3] = SHA1M_D;
     digest[4] = SHA1M_E;
 
-    sha1_transform (&final[0], &final[4], &final[8], &final[12], digest);
+    sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
 
     // prepare magic array range
 
     u32 lengthMagicArray = 0x20;
     u32 offsetMagicArray = 0;
 
-    lengthMagicArray += ((digest[0] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >> 16) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >>  8) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >>  0) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >> 16) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >>  8) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >>  0) & 0xff) % 6;
-    lengthMagicArray += ((digest[2] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[2] >> 16) & 0xff) % 6;
-    offsetMagicArray += ((digest[2] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[2] >>  0) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >> 24) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >> 16) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >>  0) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >> 24) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >> 16) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >>  0) & 0xff) % 8;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8b_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8a_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8b_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8a_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[2]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[2]) % 6;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[2]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[2]) & 7;
+    offsetMagicArray += unpack_v8d_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8c_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8d_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8c_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[4]) & 7;
 
     // final
 
@@ -278,17 +278,21 @@ KERNEL_FQ void m07801_m04 (KERN_ATTR_RULES ())
 
     // calculate
 
-    int left;
-    int off;
-
-    for (left = final_len, off = 0; left >= 56; left -= 64, off += 16)
+    if (final_len >= 56)
     {
-      sha1_transform (&final[off + 0], &final[off + 4], &final[off + 8], &final[off + 12], digest);
+      final[30] = 0;
+      final[31] = final_len * 8;
+
+      sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
+      sha1_transform (final + 16, final + 20, final + 24, final + 28, digest);
     }
+    else
+    {
+      final[14] = 0;
+      final[15] = final_len * 8;
 
-    final[off + 15] = final_len * 8;
-
-    sha1_transform (&final[off + 0], &final[off + 4], &final[off + 8], &final[off + 12], digest);
+      sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
+    }
 
     COMPARE_M_SIMD (0, 0, digest[2] & 0xffff0000, digest[1]);
   }
@@ -451,33 +455,33 @@ KERNEL_FQ void m07801_s04 (KERN_ATTR_RULES ())
     digest[3] = SHA1M_D;
     digest[4] = SHA1M_E;
 
-    sha1_transform (&final[0], &final[4], &final[8], &final[12], digest);
+    sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
 
     // prepare magic array range
 
     u32 lengthMagicArray = 0x20;
     u32 offsetMagicArray = 0;
 
-    lengthMagicArray += ((digest[0] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >> 16) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >>  8) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >>  0) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >> 16) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >>  8) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >>  0) & 0xff) % 6;
-    lengthMagicArray += ((digest[2] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[2] >> 16) & 0xff) % 6;
-    offsetMagicArray += ((digest[2] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[2] >>  0) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >> 24) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >> 16) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >>  0) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >> 24) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >> 16) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >>  0) & 0xff) % 8;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8b_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8a_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8b_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8a_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[2]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[2]) % 6;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[2]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[2]) & 7;
+    offsetMagicArray += unpack_v8d_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8c_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8d_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8c_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[4]) & 7;
 
     // final
 
@@ -538,17 +542,21 @@ KERNEL_FQ void m07801_s04 (KERN_ATTR_RULES ())
 
     // calculate
 
-    int left;
-    int off;
-
-    for (left = final_len, off = 0; left >= 56; left -= 64, off += 16)
+    if (final_len >= 56)
     {
-      sha1_transform (&final[off + 0], &final[off + 4], &final[off + 8], &final[off + 12], digest);
+      final[30] = 0;
+      final[31] = final_len * 8;
+
+      sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
+      sha1_transform (final + 16, final + 20, final + 24, final + 28, digest);
     }
+    else
+    {
+      final[14] = 0;
+      final[15] = final_len * 8;
 
-    final[off + 15] = final_len * 8;
-
-    sha1_transform (&final[off + 0], &final[off + 4], &final[off + 8], &final[off + 12], digest);
+      sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
+    }
 
     COMPARE_S_SIMD (0, 0, digest[2] & 0xffff0000, digest[1]);
   }
diff --git a/OpenCL/m07801_a1-optimized.cl b/OpenCL/m07801_a1-optimized.cl
index 8d055619c..ef836a019 100644
--- a/OpenCL/m07801_a1-optimized.cl
+++ b/OpenCL/m07801_a1-optimized.cl
@@ -249,33 +249,33 @@ KERNEL_FQ void m07801_m04 (KERN_ATTR_BASIC ())
     digest[3] = SHA1M_D;
     digest[4] = SHA1M_E;
 
-    sha1_transform (&final[0], &final[4], &final[8], &final[12], digest);
+    sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
 
     // prepare magic array range
 
     u32 lengthMagicArray = 0x20;
     u32 offsetMagicArray = 0;
 
-    lengthMagicArray += ((digest[0] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >> 16) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >>  8) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >>  0) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >> 16) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >>  8) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >>  0) & 0xff) % 6;
-    lengthMagicArray += ((digest[2] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[2] >> 16) & 0xff) % 6;
-    offsetMagicArray += ((digest[2] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[2] >>  0) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >> 24) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >> 16) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >>  0) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >> 24) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >> 16) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >>  0) & 0xff) % 8;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8b_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8a_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8b_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8a_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[2]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[2]) % 6;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[2]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[2]) & 7;
+    offsetMagicArray += unpack_v8d_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8c_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8d_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8c_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[4]) & 7;
 
     // final
 
@@ -336,17 +336,21 @@ KERNEL_FQ void m07801_m04 (KERN_ATTR_BASIC ())
 
     // calculate
 
-    int left;
-    int off;
-
-    for (left = final_len, off = 0; left >= 56; left -= 64, off += 16)
+    if (final_len >= 56)
     {
-      sha1_transform (&final[off + 0], &final[off + 4], &final[off + 8], &final[off + 12], digest);
+      final[30] = 0;
+      final[31] = final_len * 8;
+
+      sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
+      sha1_transform (final + 16, final + 20, final + 24, final + 28, digest);
     }
+    else
+    {
+      final[14] = 0;
+      final[15] = final_len * 8;
 
-    final[off + 15] = final_len * 8;
-
-    sha1_transform (&final[off + 0], &final[off + 4], &final[off + 8], &final[off + 12], digest);
+      sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
+    }
 
     COMPARE_M_SIMD (0, 0, digest[2] & 0xffff0000, digest[1]);
   }
@@ -569,33 +573,33 @@ KERNEL_FQ void m07801_s04 (KERN_ATTR_BASIC ())
     digest[3] = SHA1M_D;
     digest[4] = SHA1M_E;
 
-    sha1_transform (&final[0], &final[4], &final[8], &final[12], digest);
+    sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
 
     // prepare magic array range
 
     u32 lengthMagicArray = 0x20;
     u32 offsetMagicArray = 0;
 
-    lengthMagicArray += ((digest[0] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >> 16) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >>  8) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >>  0) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >> 16) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >>  8) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >>  0) & 0xff) % 6;
-    lengthMagicArray += ((digest[2] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[2] >> 16) & 0xff) % 6;
-    offsetMagicArray += ((digest[2] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[2] >>  0) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >> 24) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >> 16) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >>  0) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >> 24) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >> 16) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >>  0) & 0xff) % 8;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8b_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8a_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8b_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8a_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[2]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[2]) % 6;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[2]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[2]) & 7;
+    offsetMagicArray += unpack_v8d_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8c_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8d_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8c_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[4]) & 7;
 
     // final
 
@@ -656,17 +660,21 @@ KERNEL_FQ void m07801_s04 (KERN_ATTR_BASIC ())
 
     // calculate
 
-    int left;
-    int off;
-
-    for (left = final_len, off = 0; left >= 56; left -= 64, off += 16)
+    if (final_len >= 56)
     {
-      sha1_transform (&final[off + 0], &final[off + 4], &final[off + 8], &final[off + 12], digest);
+      final[30] = 0;
+      final[31] = final_len * 8;
+
+      sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
+      sha1_transform (final + 16, final + 20, final + 24, final + 28, digest);
     }
+    else
+    {
+      final[14] = 0;
+      final[15] = final_len * 8;
 
-    final[off + 15] = final_len * 8;
-
-    sha1_transform (&final[off + 0], &final[off + 4], &final[off + 8], &final[off + 12], digest);
+      sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
+    }
 
     COMPARE_S_SIMD (0, 0, digest[2] & 0xffff0000, digest[1]);
   }
diff --git a/OpenCL/m07801_a3-optimized.cl b/OpenCL/m07801_a3-optimized.cl
index 7de9f2a11..59bc222cd 100644
--- a/OpenCL/m07801_a3-optimized.cl
+++ b/OpenCL/m07801_a3-optimized.cl
@@ -165,33 +165,33 @@ DECLSPEC void m07801m (u32 *w0, u32 *w1, u32 *w2, u32 *w3, const u32 pw_len, KER
     digest[3] = SHA1M_D;
     digest[4] = SHA1M_E;
 
-    sha1_transform (&final[0], &final[4], &final[8], &final[12], digest);
+    sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
 
     // prepare magic array range
 
     u32 lengthMagicArray = 0x20;
     u32 offsetMagicArray = 0;
 
-    lengthMagicArray += ((digest[0] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >> 16) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >>  8) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >>  0) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >> 16) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >>  8) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >>  0) & 0xff) % 6;
-    lengthMagicArray += ((digest[2] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[2] >> 16) & 0xff) % 6;
-    offsetMagicArray += ((digest[2] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[2] >>  0) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >> 24) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >> 16) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >>  0) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >> 24) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >> 16) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >>  0) & 0xff) % 8;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8b_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8a_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8b_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8a_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[2]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[2]) % 6;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[2]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[2]) & 7;
+    offsetMagicArray += unpack_v8d_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8c_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8d_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8c_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[4]) & 7;
 
     // final
 
@@ -252,17 +252,21 @@ DECLSPEC void m07801m (u32 *w0, u32 *w1, u32 *w2, u32 *w3, const u32 pw_len, KER
 
     // calculate
 
-    int left;
-    int off;
-
-    for (left = final_len, off = 0; left >= 56; left -= 64, off += 16)
+    if (final_len >= 56)
     {
-      sha1_transform (&final[off + 0], &final[off + 4], &final[off + 8], &final[off + 12], digest);
+      final[30] = 0;
+      final[31] = final_len * 8;
+
+      sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
+      sha1_transform (final + 16, final + 20, final + 24, final + 28, digest);
     }
+    else
+    {
+      final[14] = 0;
+      final[15] = final_len * 8;
 
-    final[off + 15] = final_len * 8;
-
-    sha1_transform (&final[off + 0], &final[off + 4], &final[off + 8], &final[off + 12], digest);
+      sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
+    }
 
     COMPARE_M_SIMD (0, 0, digest[2] & 0xffff0000, digest[1]);
   }
@@ -393,33 +397,33 @@ DECLSPEC void m07801s (u32 *w0, u32 *w1, u32 *w2, u32 *w3, const u32 pw_len, KER
     digest[3] = SHA1M_D;
     digest[4] = SHA1M_E;
 
-    sha1_transform (&final[0], &final[4], &final[8], &final[12], digest);
+    sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
 
     // prepare magic array range
 
     u32 lengthMagicArray = 0x20;
     u32 offsetMagicArray = 0;
 
-    lengthMagicArray += ((digest[0] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >> 16) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >>  8) & 0xff) % 6;
-    lengthMagicArray += ((digest[0] >>  0) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >> 16) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >>  8) & 0xff) % 6;
-    lengthMagicArray += ((digest[1] >>  0) & 0xff) % 6;
-    lengthMagicArray += ((digest[2] >> 24) & 0xff) % 6;
-    lengthMagicArray += ((digest[2] >> 16) & 0xff) % 6;
-    offsetMagicArray += ((digest[2] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[2] >>  0) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >> 24) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >> 16) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[3] >>  0) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >> 24) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >> 16) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >>  8) & 0xff) % 8;
-    offsetMagicArray += ((digest[4] >>  0) & 0xff) % 8;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8b_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8a_from_v32_S (digest[0]) % 6;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8b_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8a_from_v32_S (digest[1]) % 6;
+    lengthMagicArray += unpack_v8d_from_v32_S (digest[2]) % 6;
+    lengthMagicArray += unpack_v8c_from_v32_S (digest[2]) % 6;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[2]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[2]) & 7;
+    offsetMagicArray += unpack_v8d_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8c_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[3]) & 7;
+    offsetMagicArray += unpack_v8d_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8c_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8b_from_v32_S (digest[4]) & 7;
+    offsetMagicArray += unpack_v8a_from_v32_S (digest[4]) & 7;
 
     // final
 
@@ -480,17 +484,21 @@ DECLSPEC void m07801s (u32 *w0, u32 *w1, u32 *w2, u32 *w3, const u32 pw_len, KER
 
     // calculate
 
-    int left;
-    int off;
-
-    for (left = final_len, off = 0; left >= 56; left -= 64, off += 16)
+    if (final_len >= 56)
     {
-      sha1_transform (&final[off + 0], &final[off + 4], &final[off + 8], &final[off + 12], digest);
+      final[30] = 0;
+      final[31] = final_len * 8;
+
+      sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
+      sha1_transform (final + 16, final + 20, final + 24, final + 28, digest);
     }
+    else
+    {
+      final[14] = 0;
+      final[15] = final_len * 8;
 
-    final[off + 15] = final_len * 8;
-
-    sha1_transform (&final[off + 0], &final[off + 4], &final[off + 8], &final[off + 12], digest);
+      sha1_transform (final +  0, final +  4, final +  8, final + 12, digest);
+    }
 
     COMPARE_S_SIMD (0, 0, digest[2] & 0xffff0000, digest[1]);
   }