diff --git a/.appveyor.yml b/.appveyor.yml
index 31a726934..d2cac8213 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -12,14 +12,16 @@ environment:
       CYG_SETUP: setup-x86.exe
       BASH: C:\cygwin\bin\bash
       CC: gcc
-    - MSYSTEM: MINGW64
-      MSYS_CACHE: C:\msys64\var\cache\pacman\pkg
-      BASH: C:\msys64\usr\bin\bash
-      CC: gcc
-    - MSYSTEM: MINGW32
-      MSYS_CACHE: C:\msys64\var\cache\pacman\pkg
-      BASH: C:\msys64\usr\bin\bash
-      CC: gcc
+    # Disable MINGW test. It seems AppVeyor is no longer supporting MSYS2. Not a hashcat problem.
+    # See BUILD_MSYS2.md for local test
+    #- MSYSTEM: MINGW64
+    #  MSYS_CACHE: C:\msys64\var\cache\pacman\pkg
+    #  BASH: C:\msys64\usr\bin\bash
+    #  CC: gcc
+    #- MSYSTEM: MINGW32
+    #  MSYS_CACHE: C:\msys64\var\cache\pacman\pkg
+    #  BASH: C:\msys64\usr\bin\bash
+    #  CC: gcc
 
 # if we have too many commits at the same time, we might need to download more than just the last commit for appveyor to succeed
 # otherwise we get the error: "fatal: reference is not a tree <commit>"
@@ -33,14 +35,15 @@ install:
   - ps: if (Test-Path Env:\CYG_ROOT) { Start-FileDownload "https://cygwin.com/$env:CYG_SETUP" -FileName "$env:CYG_SETUP" }
   - if defined CYG_ROOT (%CYG_SETUP% --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --packages "%CYG_PACKAGES%" --upgrade-also)
   # (temporary?) problem with msys/pacman/objc/ada (see https://github.com/msys2/msys2/wiki/FAQ)
-  - if defined MSYSTEM (%BASH% -lc "pacman -Rns --noconfirm mingw-w64-{i686,x86_64}-gcc-ada mingw-w64-{i686,x86_64}-gcc-objc")
+  #- if defined MSYSTEM (%BASH% -lc "pacman -Rns --noconfirm mingw-w64-{i686,x86_64}-gcc-ada mingw-w64-{i686,x86_64}-gcc-objc")
   # temporary fix for MSYS revoked/new signing keys:
-  - if defined MSYSTEM (%BASH% -lc "curl https://pastebin.com/raw/e0y4Ky9U | bash")
-  - if defined MSYSTEM (%BASH% -lc "pacman -Suuy --noconfirm")
+  #- if defined MSYSTEM (%BASH% -lc "curl https://pastebin.com/raw/e0y4Ky9U | bash")
+  #- if defined MSYSTEM (%BASH% -lc "pacman -Suuy --noconfirm")
   # the following line is not a duplicate line:
   # it is necessary to upgrade the MSYS base files and after that all the packages
   # the 2 separate commands/lines are required because a new shell is necessary for each step
-  - if defined MSYSTEM (%BASH% -lc "pacman -Suuy --noconfirm")
+  #- if defined MSYSTEM (%BASH% -lc "pacman -Suuy --noconfirm")
+  #- if defined MSYSTEM (%BASH% -lc "pacman -S --needed --noconfirm git make gcc libiconv-devel")
 
 build_script:
   - if defined BASH (%BASH% -lc "cd $(cygpath ${APPVEYOR_BUILD_FOLDER}) && make")
diff --git a/BUILD_WSL.md b/BUILD_WSL.md
index 814eaa326..115c3772b 100644
--- a/BUILD_WSL.md
+++ b/BUILD_WSL.md
@@ -2,13 +2,17 @@
 
 Tested on Windows 10 x64, should also work to build hashcat for Windows on Linux.
 
+I had it tested with WSL2 using Ubuntu_2004.2020.424.0_x64.appx.
+
+Make sure to have the system upgraded after install (otherwise it will fail to find the gcc-mingw-w64-x86-64 package).
+
 ### Installation ###
 
 Enable WSL.
 
 Press the win + r key on your keyboard simultaneously and in the "Run" popup window type bash and make sure to install additional dependencies necessary for hashcat compilation
 ```
-sudo apt install gcc-mingw-w64-x86-64 make git
+sudo apt install gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 make git
 git clone https://github.com/hashcat/hashcat
 git clone https://github.com/win-iconv/win-iconv
 cd win-iconv/
@@ -33,4 +37,4 @@ cd "C:\Users\user\hashcat"
 and start hashcat by typing
 ```
 hashcat.exe
-```
\ No newline at end of file
+```
diff --git a/OpenCL/inc_types.h b/OpenCL/inc_types.h
index 0c6218156..9a5173c54 100644
--- a/OpenCL/inc_types.h
+++ b/OpenCL/inc_types.h
@@ -171,6 +171,9 @@ inline __device__ u32x operator -  (const u32x a, const u32x b) { return u32x ((
 inline __device__ u32x operator *  (const u32x a, const u32  b) { return u32x ((a.s0 *  b),    (a.s1 *  b)   );  }
 inline __device__ u32x operator *  (const u32x a, const u32x b) { return u32x ((a.s0 *  b.s0), (a.s1 *  b.s1));  }
 
+inline __device__ u32x operator %  (const u32x a, const u32  b) { return u32x ((a.s0 %  b),    (a.s1 %  b)   );  }
+inline __device__ u32x operator %  (const u32x a, const u32x b) { return u32x ((a.s0 %  b.s0), (a.s1 %  b.s1));  }
+
 inline __device__ u32x operator ~  (const u32x a) { return u32x (~a.s0, ~a.s1); }
 
 inline __device__ bool operator != (const u64x a, const u64  b) { return ((a.s0 != b)    && (a.s1 != b));    }
@@ -224,6 +227,9 @@ inline __device__ u64x operator -  (const u64x a, const u64x b) { return u64x ((
 inline __device__ u64x operator *  (const u64x a, const u64  b) { return u64x ((a.s0 *  b),    (a.s1 *  b)   );  }
 inline __device__ u64x operator *  (const u64x a, const u64x b) { return u64x ((a.s0 *  b.s0), (a.s1 *  b.s1));  }
 
+inline __device__ u64x operator %  (const u64x a, const u64  b) { return u64x ((a.s0 %  b),    (a.s1 %  b)   );  }
+inline __device__ u64x operator %  (const u64x a, const u64x b) { return u64x ((a.s0 %  b.s0), (a.s1 %  b.s1));  }
+
 inline __device__ u64x operator ~  (const u64x a) { return u64x (~a.s0, ~a.s1); }
 
 #endif
@@ -337,6 +343,9 @@ inline __device__ u32x operator -  (const u32x a, const u32x b) { return u32x ((
 inline __device__ u32x operator *  (const u32x a, const u32  b) { return u32x ((a.s0 *  b),    (a.s1 *  b)   , (a.s2 *  b),    (a.s3 *  b)   );  }
 inline __device__ u32x operator *  (const u32x a, const u32x b) { return u32x ((a.s0 *  b.s0), (a.s1 *  b.s1), (a.s2 *  b.s2), (a.s3 *  b.s3));  }
 
+inline __device__ u32x operator %  (const u32x a, const u32  b) { return u32x ((a.s0 %  b),    (a.s1 %  b)   , (a.s2 %  b),    (a.s3 %  b)   );  }
+inline __device__ u32x operator %  (const u32x a, const u32x b) { return u32x ((a.s0 %  b.s0), (a.s1 %  b.s1), (a.s2 %  b.s2), (a.s3 %  b.s3));  }
+
 inline __device__ u32x operator ~  (const u32x a) { return u32x (~a.s0, ~a.s1, ~a.s2, ~a.s3); }
 
 inline __device__ bool operator != (const u64x a, const u64  b) { return ((a.s0 != b)    && (a.s1 != b)    && (a.s2 != b)    && (a.s3 != b)   ); }
@@ -390,6 +399,9 @@ inline __device__ u64x operator -  (const u64x a, const u64x b) { return u64x ((
 inline __device__ u64x operator *  (const u64x a, const u64  b) { return u64x ((a.s0 *  b),    (a.s1 *  b)   , (a.s2 *  b),    (a.s3 *  b)   );  }
 inline __device__ u64x operator *  (const u64x a, const u64x b) { return u64x ((a.s0 *  b.s0), (a.s1 *  b.s1), (a.s2 *  b.s2), (a.s3 *  b.s3));  }
 
+inline __device__ u64x operator %  (const u64x a, const u32  b) { return u64x ((a.s0 %  b),    (a.s1 %  b)   , (a.s2 %  b),    (a.s3 %  b)   );  }
+inline __device__ u64x operator %  (const u64x a, const u64x b) { return u64x ((a.s0 %  b.s0), (a.s1 %  b.s1), (a.s2 %  b.s2), (a.s3 %  b.s3));  }
+
 inline __device__ u64x operator ~  (const u64x a) { return u64x (~a.s0, ~a.s1, ~a.s2, ~a.s3); }
 
 #endif
@@ -519,6 +531,9 @@ inline __device__ u32x operator -  (const u32x a, const u32x b) { return u32x ((
 inline __device__ u32x operator *  (const u32x a, const u32  b) { return u32x ((a.s0 *  b),    (a.s1 *  b)   , (a.s2 *  b),    (a.s3 *  b)   , (a.s4 *  b),    (a.s5 *  b)   , (a.s6 *  b),    (a.s7 *  b)   );  }
 inline __device__ u32x operator *  (const u32x a, const u32x b) { return u32x ((a.s0 *  b.s0), (a.s1 *  b.s1), (a.s2 *  b.s2), (a.s3 *  b.s3), (a.s4 *  b.s4), (a.s5 *  b.s5), (a.s6 *  b.s6), (a.s7 *  b.s7));  }
 
+inline __device__ u32x operator %  (const u32x a, const u32  b) { return u32x ((a.s0 %  b),    (a.s1 %  b)   , (a.s2 %  b),    (a.s3 %  b)   , (a.s4 %  b),    (a.s5 %  b)   , (a.s6 %  b),    (a.s7 %  b)   );  }
+inline __device__ u32x operator %  (const u32x a, const u32x b) { return u32x ((a.s0 %  b.s0), (a.s1 %  b.s1), (a.s2 %  b.s2), (a.s3 %  b.s3), (a.s4 %  b.s4), (a.s5 %  b.s5), (a.s6 %  b.s6), (a.s7 %  b.s7));  }
+
 inline __device__ u32x operator ~  (const u32x a) { return u32x (~a.s0, ~a.s1, ~a.s2, ~a.s3, ~a.s4, ~a.s5, ~a.s6, ~a.s7); }
 
 inline __device__ bool operator != (const u64x a, const u64  b) { return ((a.s0 != b)    && (a.s1 != b)    && (a.s2 != b)    && (a.s3 != b)    && (a.s4 != b)    && (a.s5 != b)    && (a.s6 != b)    && (a.s7 != b)   ); }
@@ -572,6 +587,9 @@ inline __device__ u64x operator -  (const u64x a, const u64x b) { return u64x ((
 inline __device__ u64x operator *  (const u64x a, const u64  b) { return u64x ((a.s0 *  b),    (a.s1 *  b)   , (a.s2 *  b),    (a.s3 *  b)   , (a.s4 *  b),    (a.s5 *  b)   , (a.s6 *  b),    (a.s7 *  b)   );  }
 inline __device__ u64x operator *  (const u64x a, const u64x b) { return u64x ((a.s0 *  b.s0), (a.s1 *  b.s1), (a.s2 *  b.s2), (a.s3 *  b.s3), (a.s4 *  b.s4), (a.s5 *  b.s5), (a.s6 *  b.s6), (a.s7 *  b.s7));  }
 
+inline __device__ u64x operator %  (const u64x a, const u64  b) { return u64x ((a.s0 %  b),    (a.s1 %  b)   , (a.s2 %  b),    (a.s3 %  b)   , (a.s4 %  b),    (a.s5 %  b)   , (a.s6 %  b),    (a.s7 %  b)   );  }
+inline __device__ u64x operator %  (const u64x a, const u64x b) { return u64x ((a.s0 %  b.s0), (a.s1 %  b.s1), (a.s2 %  b.s2), (a.s3 %  b.s3), (a.s4 %  b.s4), (a.s5 %  b.s5), (a.s6 %  b.s6), (a.s7 %  b.s7));  }
+
 inline __device__ u64x operator ~  (const u64x a) { return u64x (~a.s0, ~a.s1, ~a.s2, ~a.s3, ~a.s4, ~a.s5, ~a.s6, ~a.s7); }
 
 #endif
@@ -733,6 +751,9 @@ inline __device__ u32x operator -  (const u32x a, const u32x b) { return u32x ((
 inline __device__ u32x operator *  (const u32x a, const u32  b) { return u32x ((a.s0 *  b),    (a.s1 *  b)   , (a.s2 *  b),    (a.s3 *  b)   , (a.s4 *  b),    (a.s5 *  b)   , (a.s6 *  b),    (a.s7 *  b),    (a.s8 *  b),    (a.s9 *  b)   , (a.sa *  b),    (a.sb *  b)   , (a.sc *  b),    (a.sd *  b)   , (a.se *  b),    (a.sf *  b)   );  }
 inline __device__ u32x operator *  (const u32x a, const u32x b) { return u32x ((a.s0 *  b.s0), (a.s1 *  b.s1), (a.s2 *  b.s2), (a.s3 *  b.s3), (a.s4 *  b.s4), (a.s5 *  b.s5), (a.s6 *  b.s6), (a.s7 *  b.s7), (a.s8 *  b.s8), (a.s9 *  b.s9), (a.sa *  b.sa), (a.sb *  b.sb), (a.sc *  b.sc), (a.sd *  b.sd), (a.se *  b.se), (a.sf *  b.sf));  }
 
+inline __device__ u32x operator %  (const u32x a, const u32  b) { return u32x ((a.s0 %  b),    (a.s1 %  b)   , (a.s2 %  b),    (a.s3 %  b)   , (a.s4 %  b),    (a.s5 %  b)   , (a.s6 %  b),    (a.s7 %  b),    (a.s8 %  b),    (a.s9 %  b)   , (a.sa %  b),    (a.sb %  b)   , (a.sc %  b),    (a.sd %  b)   , (a.se %  b),    (a.sf %  b)   );  }
+inline __device__ u32x operator %  (const u32x a, const u32x b) { return u32x ((a.s0 %  b.s0), (a.s1 %  b.s1), (a.s2 %  b.s2), (a.s3 %  b.s3), (a.s4 %  b.s4), (a.s5 %  b.s5), (a.s6 %  b.s6), (a.s7 %  b.s7), (a.s8 %  b.s8), (a.s9 %  b.s9), (a.sa %  b.sa), (a.sb %  b.sb), (a.sc %  b.sc), (a.sd %  b.sd), (a.se %  b.se), (a.sf %  b.sf));  }
+
 inline __device__ u32x operator ~  (const u32x a) { return u32x (~a.s0, ~a.s1, ~a.s2, ~a.s3, ~a.s4, ~a.s5, ~a.s6, ~a.s7, ~a.s8, ~a.s9, ~a.sa, ~a.sb, ~a.sc, ~a.sd, ~a.se, ~a.sf); }
 
 inline __device__ bool operator != (const u64x a, const u64  b) { return ((a.s0 != b)    && (a.s1 != b)    && (a.s2 != b)    && (a.s3 != b)    && (a.s4 != b)    && (a.s5 != b)    && (a.s6 != b)    && (a.s7 != b)    && (a.s8 != b)    && (a.s9 != b)    && (a.sa != b)    && (a.sb != b)    && (a.sc != b)    && (a.sd != b)    && (a.se != b)    && (a.sf != b)   ); }
@@ -786,6 +807,9 @@ inline __device__ u64x operator -  (const u64x a, const u64x b) { return u64x ((
 inline __device__ u64x operator *  (const u64x a, const u64  b) { return u64x ((a.s0 *  b),    (a.s1 *  b)   , (a.s2 *  b),    (a.s3 *  b)   , (a.s4 *  b),    (a.s5 *  b)   , (a.s6 *  b),    (a.s7 *  b),    (a.s8 *  b),    (a.s9 *  b)   , (a.sa *  b),    (a.sb *  b)   , (a.sc *  b),    (a.sd *  b)   , (a.se *  b),    (a.sf *  b)   );  }
 inline __device__ u64x operator *  (const u64x a, const u64x b) { return u64x ((a.s0 *  b.s0), (a.s1 *  b.s1), (a.s2 *  b.s2), (a.s3 *  b.s3), (a.s4 *  b.s4), (a.s5 *  b.s5), (a.s6 *  b.s6), (a.s7 *  b.s7), (a.s8 *  b.s8), (a.s9 *  b.s9), (a.sa *  b.sa), (a.sb *  b.sb), (a.sc *  b.sc), (a.sd *  b.sd), (a.se *  b.se), (a.sf *  b.sf));  }
 
+inline __device__ u64x operator %  (const u64x a, const u64  b) { return u64x ((a.s0 %  b),    (a.s1 %  b)   , (a.s2 %  b),    (a.s3 %  b)   , (a.s4 %  b),    (a.s5 %  b)   , (a.s6 %  b),    (a.s7 %  b),    (a.s8 %  b),    (a.s9 %  b)   , (a.sa %  b),    (a.sb %  b)   , (a.sc %  b),    (a.sd %  b)   , (a.se %  b),    (a.sf %  b)   );  }
+inline __device__ u64x operator %  (const u64x a, const u64x b) { return u64x ((a.s0 %  b.s0), (a.s1 %  b.s1), (a.s2 %  b.s2), (a.s3 %  b.s3), (a.s4 %  b.s4), (a.s5 %  b.s5), (a.s6 %  b.s6), (a.s7 %  b.s7), (a.s8 %  b.s8), (a.s9 %  b.s9), (a.sa %  b.sa), (a.sb %  b.sb), (a.sc %  b.sc), (a.sd %  b.sd), (a.se %  b.se), (a.sf %  b.sf));  }
+
 inline __device__ u64x operator ~  (const u64x a) { return u64x (~a.s0, ~a.s1, ~a.s2, ~a.s3, ~a.s4, ~a.s5, ~a.s6, ~a.s7, ~a.s8, ~a.s9, ~a.sa, ~a.sb, ~a.sc, ~a.sd, ~a.se, ~a.sf); }
 
 #endif
diff --git a/OpenCL/m24610-pure.cl b/OpenCL/m24610-pure.cl
new file mode 100644
index 000000000..aad6b6729
--- /dev/null
+++ b/OpenCL/m24610-pure.cl
@@ -0,0 +1,346 @@
+/**
+ * Author......: See docs/credits.txt
+ * License.....: MIT
+ */
+
+#define NEW_SIMD_CODE
+
+#ifdef KERNEL_STATIC
+#include "inc_vendor.h"
+#include "inc_types.h"
+#include "inc_platform.cl"
+#include "inc_common.cl"
+#include "inc_simd.cl"
+#include "inc_hash_sha1.cl"
+#include "inc_cipher_aes.cl"
+#endif
+
+#define COMPARE_S "inc_comp_single.cl"
+#define COMPARE_M "inc_comp_multi.cl"
+
+typedef struct sqlcipher_sha1_tmp
+{
+  u32  ipad[5];
+  u32  opad[5];
+
+  u32  dgst[10];
+  u32  out[10];
+
+} sqlcipher_sha1_tmp_t;
+
+typedef struct sqlcipher
+{
+  u32 iv_buf[4];
+  u32 data_buf[4];
+
+  u32 type;
+
+} sqlcipher_t;
+
+DECLSPEC void hmac_sha1_run_V (u32x *w0, u32x *w1, u32x *w2, u32x *w3, u32x *ipad, u32x *opad, u32x *digest)
+{
+  digest[0] = ipad[0];
+  digest[1] = ipad[1];
+  digest[2] = ipad[2];
+  digest[3] = ipad[3];
+  digest[4] = ipad[4];
+
+  sha1_transform_vector (w0, w1, w2, w3, digest);
+
+  w0[0] = digest[0];
+  w0[1] = digest[1];
+  w0[2] = digest[2];
+  w0[3] = digest[3];
+  w1[0] = digest[4];
+  w1[1] = 0x80000000;
+  w1[2] = 0;
+  w1[3] = 0;
+  w2[0] = 0;
+  w2[1] = 0;
+  w2[2] = 0;
+  w2[3] = 0;
+  w3[0] = 0;
+  w3[1] = 0;
+  w3[2] = 0;
+  w3[3] = (64 + 20) * 8;
+
+  digest[0] = opad[0];
+  digest[1] = opad[1];
+  digest[2] = opad[2];
+  digest[3] = opad[3];
+  digest[4] = opad[4];
+
+  sha1_transform_vector (w0, w1, w2, w3, digest);
+}
+
+KERNEL_FQ void m24610_init (KERN_ATTR_TMPS_ESALT (sqlcipher_sha1_tmp_t, sqlcipher_t))
+{
+  /**
+   * base
+   */
+
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  sha1_hmac_ctx_t sha1_hmac_ctx;
+
+  sha1_hmac_init_global_swap (&sha1_hmac_ctx, pws[gid].i, pws[gid].pw_len);
+
+  tmps[gid].ipad[0] = sha1_hmac_ctx.ipad.h[0];
+  tmps[gid].ipad[1] = sha1_hmac_ctx.ipad.h[1];
+  tmps[gid].ipad[2] = sha1_hmac_ctx.ipad.h[2];
+  tmps[gid].ipad[3] = sha1_hmac_ctx.ipad.h[3];
+  tmps[gid].ipad[4] = sha1_hmac_ctx.ipad.h[4];
+
+  tmps[gid].opad[0] = sha1_hmac_ctx.opad.h[0];
+  tmps[gid].opad[1] = sha1_hmac_ctx.opad.h[1];
+  tmps[gid].opad[2] = sha1_hmac_ctx.opad.h[2];
+  tmps[gid].opad[3] = sha1_hmac_ctx.opad.h[3];
+  tmps[gid].opad[4] = sha1_hmac_ctx.opad.h[4];
+
+  sha1_hmac_update_global_swap (&sha1_hmac_ctx, salt_bufs[DIGESTS_OFFSET].salt_buf, salt_bufs[SALT_POS].salt_len);
+
+  for (u32 i = 0, j = 1; i < 8; i += 5, j += 1)
+  {
+    sha1_hmac_ctx_t sha1_hmac_ctx2 = sha1_hmac_ctx;
+
+    u32 w0[4];
+    u32 w1[4];
+    u32 w2[4];
+    u32 w3[4];
+
+    w0[0] = j;
+    w0[1] = 0;
+    w0[2] = 0;
+    w0[3] = 0;
+    w1[0] = 0;
+    w1[1] = 0;
+    w1[2] = 0;
+    w1[3] = 0;
+    w2[0] = 0;
+    w2[1] = 0;
+    w2[2] = 0;
+    w2[3] = 0;
+    w3[0] = 0;
+    w3[1] = 0;
+    w3[2] = 0;
+    w3[3] = 0;
+
+    sha1_hmac_update_64 (&sha1_hmac_ctx2, w0, w1, w2, w3, 4);
+
+    sha1_hmac_final (&sha1_hmac_ctx2);
+
+    tmps[gid].dgst[i + 0] = sha1_hmac_ctx2.opad.h[0];
+    tmps[gid].dgst[i + 1] = sha1_hmac_ctx2.opad.h[1];
+    tmps[gid].dgst[i + 2] = sha1_hmac_ctx2.opad.h[2];
+    tmps[gid].dgst[i + 3] = sha1_hmac_ctx2.opad.h[3];
+    tmps[gid].dgst[i + 4] = sha1_hmac_ctx2.opad.h[4];
+
+    tmps[gid].out[i + 0] = tmps[gid].dgst[i + 0];
+    tmps[gid].out[i + 1] = tmps[gid].dgst[i + 1];
+    tmps[gid].out[i + 2] = tmps[gid].dgst[i + 2];
+    tmps[gid].out[i + 3] = tmps[gid].dgst[i + 3];
+    tmps[gid].out[i + 4] = tmps[gid].dgst[i + 4];
+  }
+}
+
+KERNEL_FQ void m24610_loop (KERN_ATTR_TMPS_ESALT (sqlcipher_sha1_tmp_t, sqlcipher_t))
+{
+  const u64 gid = get_global_id (0);
+
+  if ((gid * VECT_SIZE) >= gid_max) return;
+
+  u32x ipad[5];
+  u32x opad[5];
+
+  ipad[0] = packv (tmps, ipad, gid, 0);
+  ipad[1] = packv (tmps, ipad, gid, 1);
+  ipad[2] = packv (tmps, ipad, gid, 2);
+  ipad[3] = packv (tmps, ipad, gid, 3);
+  ipad[4] = packv (tmps, ipad, gid, 4);
+
+  opad[0] = packv (tmps, opad, gid, 0);
+  opad[1] = packv (tmps, opad, gid, 1);
+  opad[2] = packv (tmps, opad, gid, 2);
+  opad[3] = packv (tmps, opad, gid, 3);
+  opad[4] = packv (tmps, opad, gid, 4);
+
+  for (u32 i = 0; i < 8; i += 5)
+  {
+    u32x dgst[5];
+    u32x out[5];
+
+    dgst[0] = packv (tmps, dgst, gid, i + 0);
+    dgst[1] = packv (tmps, dgst, gid, i + 1);
+    dgst[2] = packv (tmps, dgst, gid, i + 2);
+    dgst[3] = packv (tmps, dgst, gid, i + 3);
+    dgst[4] = packv (tmps, dgst, gid, i + 4);
+
+    out[0] = packv (tmps, out, gid, i + 0);
+    out[1] = packv (tmps, out, gid, i + 1);
+    out[2] = packv (tmps, out, gid, i + 2);
+    out[3] = packv (tmps, out, gid, i + 3);
+    out[4] = packv (tmps, out, gid, i + 4);
+
+    for (u32 j = 0; j < loop_cnt; j++)
+    {
+      u32x w0[4];
+      u32x w1[4];
+      u32x w2[4];
+      u32x w3[4];
+
+      w0[0] = dgst[0];
+      w0[1] = dgst[1];
+      w0[2] = dgst[2];
+      w0[3] = dgst[3];
+      w1[0] = dgst[4];
+      w1[1] = 0x80000000;
+      w1[2] = 0;
+      w1[3] = 0;
+      w2[0] = 0;
+      w2[1] = 0;
+      w2[2] = 0;
+      w2[3] = 0;
+      w3[0] = 0;
+      w3[1] = 0;
+      w3[2] = 0;
+      w3[3] = (64 + 20) * 8;
+
+      hmac_sha1_run_V (w0, w1, w2, w3, ipad, opad, dgst);
+
+      out[0] ^= dgst[0];
+      out[1] ^= dgst[1];
+      out[2] ^= dgst[2];
+      out[3] ^= dgst[3];
+      out[4] ^= dgst[4];
+    }
+
+    unpackv (tmps, dgst, gid, i + 0, dgst[0]);
+    unpackv (tmps, dgst, gid, i + 1, dgst[1]);
+    unpackv (tmps, dgst, gid, i + 2, dgst[2]);
+    unpackv (tmps, dgst, gid, i + 3, dgst[3]);
+    unpackv (tmps, dgst, gid, i + 4, dgst[4]);
+
+    unpackv (tmps, out, gid, i + 0, out[0]);
+    unpackv (tmps, out, gid, i + 1, out[1]);
+    unpackv (tmps, out, gid, i + 2, out[2]);
+    unpackv (tmps, out, gid, i + 3, out[3]);
+    unpackv (tmps, out, gid, i + 4, out[4]);
+  }
+}
+
+KERNEL_FQ void m24610_comp (KERN_ATTR_TMPS_ESALT (sqlcipher_sha1_tmp_t, sqlcipher_t))
+{
+  const u64 gid = get_global_id (0);
+  const u64 lid = get_local_id (0);
+  const u64 lsz = get_local_size (0);
+
+  /**
+   * aes shared
+   */
+
+  #ifdef REAL_SHM
+
+  LOCAL_VK u32 s_td0[256];
+  LOCAL_VK u32 s_td1[256];
+  LOCAL_VK u32 s_td2[256];
+  LOCAL_VK u32 s_td3[256];
+  LOCAL_VK u32 s_td4[256];
+
+  LOCAL_VK u32 s_te0[256];
+  LOCAL_VK u32 s_te1[256];
+  LOCAL_VK u32 s_te2[256];
+  LOCAL_VK u32 s_te3[256];
+  LOCAL_VK u32 s_te4[256];
+
+  for (u32 i = lid; i < 256; i += lsz)
+  {
+    s_td0[i] = td0[i];
+    s_td1[i] = td1[i];
+    s_td2[i] = td2[i];
+    s_td3[i] = td3[i];
+    s_td4[i] = td4[i];
+
+    s_te0[i] = te0[i];
+    s_te1[i] = te1[i];
+    s_te2[i] = te2[i];
+    s_te3[i] = te3[i];
+    s_te4[i] = te4[i];
+  }
+
+  SYNC_THREADS ();
+
+  #else
+
+  CONSTANT_AS u32a *s_td0 = td0;
+  CONSTANT_AS u32a *s_td1 = td1;
+  CONSTANT_AS u32a *s_td2 = td2;
+  CONSTANT_AS u32a *s_td3 = td3;
+  CONSTANT_AS u32a *s_td4 = td4;
+
+  CONSTANT_AS u32a *s_te0 = te0;
+  CONSTANT_AS u32a *s_te1 = te1;
+  CONSTANT_AS u32a *s_te2 = te2;
+  CONSTANT_AS u32a *s_te3 = te3;
+  CONSTANT_AS u32a *s_te4 = te4;
+
+  #endif
+
+  if (gid >= gid_max) return;
+
+  u32 ukey[8];
+
+  ukey[0] = tmps[gid].out[0];
+  ukey[1] = tmps[gid].out[1];
+  ukey[2] = tmps[gid].out[2];
+  ukey[3] = tmps[gid].out[3];
+  ukey[4] = tmps[gid].out[4];
+  ukey[5] = tmps[gid].out[5];
+  ukey[6] = tmps[gid].out[6];
+  ukey[7] = tmps[gid].out[7];
+
+  u32 ks[60];
+
+  AES256_set_decrypt_key (ks, ukey, s_te0, s_te1, s_te2, s_te3, s_td0, s_td1, s_td2, s_td3);
+
+  // first check the padding
+
+  u32 iv_buf[4];
+
+  iv_buf[0] = esalt_bufs[DIGESTS_OFFSET].iv_buf[0];
+  iv_buf[1] = esalt_bufs[DIGESTS_OFFSET].iv_buf[1];
+  iv_buf[2] = esalt_bufs[DIGESTS_OFFSET].iv_buf[2];
+  iv_buf[3] = esalt_bufs[DIGESTS_OFFSET].iv_buf[3];
+
+  u32 enc[4];
+
+  enc[0] = esalt_bufs[DIGESTS_OFFSET].data_buf[0];
+  enc[1] = esalt_bufs[DIGESTS_OFFSET].data_buf[1];
+  enc[2] = esalt_bufs[DIGESTS_OFFSET].data_buf[2];
+  enc[3] = esalt_bufs[DIGESTS_OFFSET].data_buf[3];
+
+  u32 dec[4];
+
+  aes256_decrypt (ks, enc, dec, s_td0, s_td1, s_td2, s_td3, s_td4);
+
+  dec[0] ^= iv_buf[0];
+  dec[1] ^= iv_buf[1];
+  dec[2] ^= iv_buf[2];
+  dec[3] ^= iv_buf[3];
+
+  if (dec[0] != 0) return;
+  if (dec[1] != 0) return;
+  if (dec[2] != 0) return;
+
+  const u32 r0 = esalt_bufs[DIGESTS_OFFSET].data_buf[0];
+  const u32 r1 = esalt_bufs[DIGESTS_OFFSET].data_buf[1];
+  const u32 r2 = esalt_bufs[DIGESTS_OFFSET].data_buf[2];
+  const u32 r3 = esalt_bufs[DIGESTS_OFFSET].data_buf[3];
+
+  #define il_pos 0
+
+  #ifdef KERNEL_STATIC
+  #include COMPARE_M
+  #endif
+}
diff --git a/OpenCL/m24620-pure.cl b/OpenCL/m24620-pure.cl
new file mode 100644
index 000000000..da67ba36d
--- /dev/null
+++ b/OpenCL/m24620-pure.cl
@@ -0,0 +1,385 @@
+/**
+ * Author......: See docs/credits.txt
+ * License.....: MIT
+ */
+
+#define NEW_SIMD_CODE
+
+#ifdef KERNEL_STATIC
+#include "inc_vendor.h"
+#include "inc_types.h"
+#include "inc_platform.cl"
+#include "inc_common.cl"
+#include "inc_simd.cl"
+#include "inc_hash_sha256.cl"
+#include "inc_cipher_aes.cl"
+#endif
+
+#define COMPARE_S "inc_comp_single.cl"
+#define COMPARE_M "inc_comp_multi.cl"
+
+typedef struct sqlcipher_sha256_tmp
+{
+  u32  ipad[8];
+  u32  opad[8];
+
+  u32  dgst[8];
+  u32  out[8];
+
+} sqlcipher_sha256_tmp_t;
+
+typedef struct sqlcipher
+{
+  u32 iv_buf[4];
+  u32 data_buf[4];
+
+  u32 type;
+
+} sqlcipher_t;
+
+DECLSPEC void hmac_sha256_run_V (u32x *w0, u32x *w1, u32x *w2, u32x *w3, u32x *ipad, u32x *opad, u32x *digest)
+{
+  digest[0] = ipad[0];
+  digest[1] = ipad[1];
+  digest[2] = ipad[2];
+  digest[3] = ipad[3];
+  digest[4] = ipad[4];
+  digest[5] = ipad[5];
+  digest[6] = ipad[6];
+  digest[7] = ipad[7];
+
+  sha256_transform_vector (w0, w1, w2, w3, digest);
+
+  w0[0] = digest[0];
+  w0[1] = digest[1];
+  w0[2] = digest[2];
+  w0[3] = digest[3];
+  w1[0] = digest[4];
+  w1[1] = digest[5];
+  w1[2] = digest[6];
+  w1[3] = digest[7];
+  w2[0] = 0x80000000;
+  w2[1] = 0;
+  w2[2] = 0;
+  w2[3] = 0;
+  w3[0] = 0;
+  w3[1] = 0;
+  w3[2] = 0;
+  w3[3] = (64 + 32) * 8;
+
+  digest[0] = opad[0];
+  digest[1] = opad[1];
+  digest[2] = opad[2];
+  digest[3] = opad[3];
+  digest[4] = opad[4];
+  digest[5] = opad[5];
+  digest[6] = opad[6];
+  digest[7] = opad[7];
+
+  sha256_transform_vector (w0, w1, w2, w3, digest);
+}
+
+KERNEL_FQ void m24620_init (KERN_ATTR_TMPS_ESALT (sqlcipher_sha256_tmp_t, sqlcipher_t))
+{
+  /**
+   * base
+   */
+
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  sha256_hmac_ctx_t sha256_hmac_ctx;
+
+  sha256_hmac_init_global_swap (&sha256_hmac_ctx, pws[gid].i, pws[gid].pw_len);
+
+  tmps[gid].ipad[0] = sha256_hmac_ctx.ipad.h[0];
+  tmps[gid].ipad[1] = sha256_hmac_ctx.ipad.h[1];
+  tmps[gid].ipad[2] = sha256_hmac_ctx.ipad.h[2];
+  tmps[gid].ipad[3] = sha256_hmac_ctx.ipad.h[3];
+  tmps[gid].ipad[4] = sha256_hmac_ctx.ipad.h[4];
+  tmps[gid].ipad[5] = sha256_hmac_ctx.ipad.h[5];
+  tmps[gid].ipad[6] = sha256_hmac_ctx.ipad.h[6];
+  tmps[gid].ipad[7] = sha256_hmac_ctx.ipad.h[7];
+
+  tmps[gid].opad[0] = sha256_hmac_ctx.opad.h[0];
+  tmps[gid].opad[1] = sha256_hmac_ctx.opad.h[1];
+  tmps[gid].opad[2] = sha256_hmac_ctx.opad.h[2];
+  tmps[gid].opad[3] = sha256_hmac_ctx.opad.h[3];
+  tmps[gid].opad[4] = sha256_hmac_ctx.opad.h[4];
+  tmps[gid].opad[5] = sha256_hmac_ctx.opad.h[5];
+  tmps[gid].opad[6] = sha256_hmac_ctx.opad.h[6];
+  tmps[gid].opad[7] = sha256_hmac_ctx.opad.h[7];
+
+  sha256_hmac_update_global_swap (&sha256_hmac_ctx, salt_bufs[DIGESTS_OFFSET].salt_buf, salt_bufs[SALT_POS].salt_len);
+
+  for (u32 i = 0, j = 1; i < 8; i += 8, j += 1)
+  {
+    sha256_hmac_ctx_t sha256_hmac_ctx2 = sha256_hmac_ctx;
+
+    u32 w0[4];
+    u32 w1[4];
+    u32 w2[4];
+    u32 w3[4];
+
+    w0[0] = j;
+    w0[1] = 0;
+    w0[2] = 0;
+    w0[3] = 0;
+    w1[0] = 0;
+    w1[1] = 0;
+    w1[2] = 0;
+    w1[3] = 0;
+    w2[0] = 0;
+    w2[1] = 0;
+    w2[2] = 0;
+    w2[3] = 0;
+    w3[0] = 0;
+    w3[1] = 0;
+    w3[2] = 0;
+    w3[3] = 0;
+
+    sha256_hmac_update_64 (&sha256_hmac_ctx2, w0, w1, w2, w3, 4);
+
+    sha256_hmac_final (&sha256_hmac_ctx2);
+
+    tmps[gid].dgst[i + 0] = sha256_hmac_ctx2.opad.h[0];
+    tmps[gid].dgst[i + 1] = sha256_hmac_ctx2.opad.h[1];
+    tmps[gid].dgst[i + 2] = sha256_hmac_ctx2.opad.h[2];
+    tmps[gid].dgst[i + 3] = sha256_hmac_ctx2.opad.h[3];
+    tmps[gid].dgst[i + 4] = sha256_hmac_ctx2.opad.h[4];
+    tmps[gid].dgst[i + 5] = sha256_hmac_ctx2.opad.h[5];
+    tmps[gid].dgst[i + 6] = sha256_hmac_ctx2.opad.h[6];
+    tmps[gid].dgst[i + 7] = sha256_hmac_ctx2.opad.h[7];
+
+    tmps[gid].out[i + 0] = tmps[gid].dgst[i + 0];
+    tmps[gid].out[i + 1] = tmps[gid].dgst[i + 1];
+    tmps[gid].out[i + 2] = tmps[gid].dgst[i + 2];
+    tmps[gid].out[i + 3] = tmps[gid].dgst[i + 3];
+    tmps[gid].out[i + 4] = tmps[gid].dgst[i + 4];
+    tmps[gid].out[i + 5] = tmps[gid].dgst[i + 5];
+    tmps[gid].out[i + 6] = tmps[gid].dgst[i + 6];
+    tmps[gid].out[i + 7] = tmps[gid].dgst[i + 7];
+  }
+}
+
+KERNEL_FQ void m24620_loop (KERN_ATTR_TMPS_ESALT (sqlcipher_sha256_tmp_t, sqlcipher_t))
+{
+  const u64 gid = get_global_id (0);
+
+  if ((gid * VECT_SIZE) >= gid_max) return;
+
+  u32x ipad[8];
+  u32x opad[8];
+
+  ipad[0] = packv (tmps, ipad, gid, 0);
+  ipad[1] = packv (tmps, ipad, gid, 1);
+  ipad[2] = packv (tmps, ipad, gid, 2);
+  ipad[3] = packv (tmps, ipad, gid, 3);
+  ipad[4] = packv (tmps, ipad, gid, 4);
+  ipad[5] = packv (tmps, ipad, gid, 5);
+  ipad[6] = packv (tmps, ipad, gid, 6);
+  ipad[7] = packv (tmps, ipad, gid, 7);
+
+  opad[0] = packv (tmps, opad, gid, 0);
+  opad[1] = packv (tmps, opad, gid, 1);
+  opad[2] = packv (tmps, opad, gid, 2);
+  opad[3] = packv (tmps, opad, gid, 3);
+  opad[4] = packv (tmps, opad, gid, 4);
+  opad[5] = packv (tmps, opad, gid, 5);
+  opad[6] = packv (tmps, opad, gid, 6);
+  opad[7] = packv (tmps, opad, gid, 7);
+
+  for (u32 i = 0; i < 8; i += 8)
+  {
+    u32x dgst[8];
+    u32x out[8];
+
+    dgst[0] = packv (tmps, dgst, gid, i + 0);
+    dgst[1] = packv (tmps, dgst, gid, i + 1);
+    dgst[2] = packv (tmps, dgst, gid, i + 2);
+    dgst[3] = packv (tmps, dgst, gid, i + 3);
+    dgst[4] = packv (tmps, dgst, gid, i + 4);
+    dgst[5] = packv (tmps, dgst, gid, i + 5);
+    dgst[6] = packv (tmps, dgst, gid, i + 6);
+    dgst[7] = packv (tmps, dgst, gid, i + 7);
+
+    out[0] = packv (tmps, out, gid, i + 0);
+    out[1] = packv (tmps, out, gid, i + 1);
+    out[2] = packv (tmps, out, gid, i + 2);
+    out[3] = packv (tmps, out, gid, i + 3);
+    out[4] = packv (tmps, out, gid, i + 4);
+    out[5] = packv (tmps, out, gid, i + 5);
+    out[6] = packv (tmps, out, gid, i + 6);
+    out[7] = packv (tmps, out, gid, i + 7);
+
+    for (u32 j = 0; j < loop_cnt; j++)
+    {
+      u32x w0[4];
+      u32x w1[4];
+      u32x w2[4];
+      u32x w3[4];
+
+      w0[0] = dgst[0];
+      w0[1] = dgst[1];
+      w0[2] = dgst[2];
+      w0[3] = dgst[3];
+      w1[0] = dgst[4];
+      w1[1] = dgst[5];
+      w1[2] = dgst[6];
+      w1[3] = dgst[7];
+      w2[0] = 0x80000000;
+      w2[1] = 0;
+      w2[2] = 0;
+      w2[3] = 0;
+      w3[0] = 0;
+      w3[1] = 0;
+      w3[2] = 0;
+      w3[3] = (64 + 32) * 8;
+
+      hmac_sha256_run_V (w0, w1, w2, w3, ipad, opad, dgst);
+
+      out[0] ^= dgst[0];
+      out[1] ^= dgst[1];
+      out[2] ^= dgst[2];
+      out[3] ^= dgst[3];
+      out[4] ^= dgst[4];
+      out[5] ^= dgst[5];
+      out[6] ^= dgst[6];
+      out[7] ^= dgst[7];
+    }
+
+    unpackv (tmps, dgst, gid, i + 0, dgst[0]);
+    unpackv (tmps, dgst, gid, i + 1, dgst[1]);
+    unpackv (tmps, dgst, gid, i + 2, dgst[2]);
+    unpackv (tmps, dgst, gid, i + 3, dgst[3]);
+    unpackv (tmps, dgst, gid, i + 4, dgst[4]);
+    unpackv (tmps, dgst, gid, i + 5, dgst[5]);
+    unpackv (tmps, dgst, gid, i + 6, dgst[6]);
+    unpackv (tmps, dgst, gid, i + 7, dgst[7]);
+
+    unpackv (tmps, out, gid, i + 0, out[0]);
+    unpackv (tmps, out, gid, i + 1, out[1]);
+    unpackv (tmps, out, gid, i + 2, out[2]);
+    unpackv (tmps, out, gid, i + 3, out[3]);
+    unpackv (tmps, out, gid, i + 4, out[4]);
+    unpackv (tmps, out, gid, i + 5, out[5]);
+    unpackv (tmps, out, gid, i + 6, out[6]);
+    unpackv (tmps, out, gid, i + 7, out[7]);
+  }
+}
+
+KERNEL_FQ void m24620_comp (KERN_ATTR_TMPS_ESALT (sqlcipher_sha256_tmp_t, sqlcipher_t))
+{
+  const u64 gid = get_global_id (0);
+  const u64 lid = get_local_id (0);
+  const u64 lsz = get_local_size (0);
+
+  /**
+   * aes shared
+   */
+
+  #ifdef REAL_SHM
+
+  LOCAL_VK u32 s_td0[256];
+  LOCAL_VK u32 s_td1[256];
+  LOCAL_VK u32 s_td2[256];
+  LOCAL_VK u32 s_td3[256];
+  LOCAL_VK u32 s_td4[256];
+
+  LOCAL_VK u32 s_te0[256];
+  LOCAL_VK u32 s_te1[256];
+  LOCAL_VK u32 s_te2[256];
+  LOCAL_VK u32 s_te3[256];
+  LOCAL_VK u32 s_te4[256];
+
+  for (u32 i = lid; i < 256; i += lsz)
+  {
+    s_td0[i] = td0[i];
+    s_td1[i] = td1[i];
+    s_td2[i] = td2[i];
+    s_td3[i] = td3[i];
+    s_td4[i] = td4[i];
+
+    s_te0[i] = te0[i];
+    s_te1[i] = te1[i];
+    s_te2[i] = te2[i];
+    s_te3[i] = te3[i];
+    s_te4[i] = te4[i];
+  }
+
+  SYNC_THREADS ();
+
+  #else
+
+  CONSTANT_AS u32a *s_td0 = td0;
+  CONSTANT_AS u32a *s_td1 = td1;
+  CONSTANT_AS u32a *s_td2 = td2;
+  CONSTANT_AS u32a *s_td3 = td3;
+  CONSTANT_AS u32a *s_td4 = td4;
+
+  CONSTANT_AS u32a *s_te0 = te0;
+  CONSTANT_AS u32a *s_te1 = te1;
+  CONSTANT_AS u32a *s_te2 = te2;
+  CONSTANT_AS u32a *s_te3 = te3;
+  CONSTANT_AS u32a *s_te4 = te4;
+
+  #endif
+
+  if (gid >= gid_max) return;
+
+  u32 ukey[8];
+
+  ukey[0] = tmps[gid].out[0];
+  ukey[1] = tmps[gid].out[1];
+  ukey[2] = tmps[gid].out[2];
+  ukey[3] = tmps[gid].out[3];
+  ukey[4] = tmps[gid].out[4];
+  ukey[5] = tmps[gid].out[5];
+  ukey[6] = tmps[gid].out[6];
+  ukey[7] = tmps[gid].out[7];
+
+  u32 ks[60];
+
+  AES256_set_decrypt_key (ks, ukey, s_te0, s_te1, s_te2, s_te3, s_td0, s_td1, s_td2, s_td3);
+
+  // first check the padding
+
+  u32 iv_buf[4];
+
+  iv_buf[0] = esalt_bufs[DIGESTS_OFFSET].iv_buf[0];
+  iv_buf[1] = esalt_bufs[DIGESTS_OFFSET].iv_buf[1];
+  iv_buf[2] = esalt_bufs[DIGESTS_OFFSET].iv_buf[2];
+  iv_buf[3] = esalt_bufs[DIGESTS_OFFSET].iv_buf[3];
+
+  u32 enc[4];
+
+  enc[0] = esalt_bufs[DIGESTS_OFFSET].data_buf[0];
+  enc[1] = esalt_bufs[DIGESTS_OFFSET].data_buf[1];
+  enc[2] = esalt_bufs[DIGESTS_OFFSET].data_buf[2];
+  enc[3] = esalt_bufs[DIGESTS_OFFSET].data_buf[3];
+
+  u32 dec[4];
+
+  aes256_decrypt (ks, enc, dec, s_td0, s_td1, s_td2, s_td3, s_td4);
+
+  dec[0] ^= iv_buf[0];
+  dec[1] ^= iv_buf[1];
+  dec[2] ^= iv_buf[2];
+  dec[3] ^= iv_buf[3];
+
+  if (dec[0] != 0) return;
+  if (dec[1] != 0) return;
+  if (dec[2] != 0) return;
+
+  const u32 r0 = esalt_bufs[DIGESTS_OFFSET].data_buf[0];
+  const u32 r1 = esalt_bufs[DIGESTS_OFFSET].data_buf[1];
+  const u32 r2 = esalt_bufs[DIGESTS_OFFSET].data_buf[2];
+  const u32 r3 = esalt_bufs[DIGESTS_OFFSET].data_buf[3];
+
+  #define il_pos 0
+
+  #ifdef KERNEL_STATIC
+  #include COMPARE_M
+  #endif
+}
diff --git a/OpenCL/m24630-pure.cl b/OpenCL/m24630-pure.cl
new file mode 100644
index 000000000..c54ca9a0b
--- /dev/null
+++ b/OpenCL/m24630-pure.cl
@@ -0,0 +1,441 @@
+/**
+ * Author......: See docs/credits.txt
+ * License.....: MIT
+ */
+
+#define NEW_SIMD_CODE
+
+#ifdef KERNEL_STATIC
+#include "inc_vendor.h"
+#include "inc_types.h"
+#include "inc_platform.cl"
+#include "inc_common.cl"
+#include "inc_simd.cl"
+#include "inc_hash_sha512.cl"
+#include "inc_cipher_aes.cl"
+#endif
+
+#define COMPARE_S "inc_comp_single.cl"
+#define COMPARE_M "inc_comp_multi.cl"
+
+typedef struct sqlcipher_sha512_tmp
+{
+  u64  ipad[8];
+  u64  opad[8];
+
+  u64  dgst[8];
+  u64  out[8];
+
+} sqlcipher_sha512_tmp_t;
+
+typedef struct sqlcipher
+{
+  u32 iv_buf[4];
+  u32 data_buf[4];
+
+  u32 type;
+
+} sqlcipher_t;
+
+DECLSPEC void hmac_sha512_run_V (u32x *w0, u32x *w1, u32x *w2, u32x *w3, u32x *w4, u32x *w5, u32x *w6, u32x *w7, u64x *ipad, u64x *opad, u64x *digest)
+{
+  digest[0] = ipad[0];
+  digest[1] = ipad[1];
+  digest[2] = ipad[2];
+  digest[3] = ipad[3];
+  digest[4] = ipad[4];
+  digest[5] = ipad[5];
+  digest[6] = ipad[6];
+  digest[7] = ipad[7];
+
+  sha512_transform_vector (w0, w1, w2, w3, w4, w5, w6, w7, digest);
+
+  w0[0] = h32_from_64 (digest[0]);
+  w0[1] = l32_from_64 (digest[0]);
+  w0[2] = h32_from_64 (digest[1]);
+  w0[3] = l32_from_64 (digest[1]);
+  w1[0] = h32_from_64 (digest[2]);
+  w1[1] = l32_from_64 (digest[2]);
+  w1[2] = h32_from_64 (digest[3]);
+  w1[3] = l32_from_64 (digest[3]);
+  w2[0] = h32_from_64 (digest[4]);
+  w2[1] = l32_from_64 (digest[4]);
+  w2[2] = h32_from_64 (digest[5]);
+  w2[3] = l32_from_64 (digest[5]);
+  w3[0] = h32_from_64 (digest[6]);
+  w3[1] = l32_from_64 (digest[6]);
+  w3[2] = h32_from_64 (digest[7]);
+  w3[3] = l32_from_64 (digest[7]);
+  w4[0] = 0x80000000;
+  w4[1] = 0;
+  w4[2] = 0;
+  w4[3] = 0;
+  w5[0] = 0;
+  w5[1] = 0;
+  w5[2] = 0;
+  w5[3] = 0;
+  w6[0] = 0;
+  w6[1] = 0;
+  w6[2] = 0;
+  w6[3] = 0;
+  w7[0] = 0;
+  w7[1] = 0;
+  w7[2] = 0;
+  w7[3] = (128 + 64) * 8;
+
+  digest[0] = opad[0];
+  digest[1] = opad[1];
+  digest[2] = opad[2];
+  digest[3] = opad[3];
+  digest[4] = opad[4];
+  digest[5] = opad[5];
+  digest[6] = opad[6];
+  digest[7] = opad[7];
+
+  sha512_transform_vector (w0, w1, w2, w3, w4, w5, w6, w7, digest);
+}
+
+KERNEL_FQ void m24630_init (KERN_ATTR_TMPS_ESALT (sqlcipher_sha512_tmp_t, sqlcipher_t))
+{
+  /**
+   * base
+   */
+
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  sha512_hmac_ctx_t sha512_hmac_ctx;
+
+  sha512_hmac_init_global_swap (&sha512_hmac_ctx, pws[gid].i, pws[gid].pw_len);
+
+  tmps[gid].ipad[0] = sha512_hmac_ctx.ipad.h[0];
+  tmps[gid].ipad[1] = sha512_hmac_ctx.ipad.h[1];
+  tmps[gid].ipad[2] = sha512_hmac_ctx.ipad.h[2];
+  tmps[gid].ipad[3] = sha512_hmac_ctx.ipad.h[3];
+  tmps[gid].ipad[4] = sha512_hmac_ctx.ipad.h[4];
+  tmps[gid].ipad[5] = sha512_hmac_ctx.ipad.h[5];
+  tmps[gid].ipad[6] = sha512_hmac_ctx.ipad.h[6];
+  tmps[gid].ipad[7] = sha512_hmac_ctx.ipad.h[7];
+
+  tmps[gid].opad[0] = sha512_hmac_ctx.opad.h[0];
+  tmps[gid].opad[1] = sha512_hmac_ctx.opad.h[1];
+  tmps[gid].opad[2] = sha512_hmac_ctx.opad.h[2];
+  tmps[gid].opad[3] = sha512_hmac_ctx.opad.h[3];
+  tmps[gid].opad[4] = sha512_hmac_ctx.opad.h[4];
+  tmps[gid].opad[5] = sha512_hmac_ctx.opad.h[5];
+  tmps[gid].opad[6] = sha512_hmac_ctx.opad.h[6];
+  tmps[gid].opad[7] = sha512_hmac_ctx.opad.h[7];
+
+  sha512_hmac_update_global_swap (&sha512_hmac_ctx, salt_bufs[DIGESTS_OFFSET].salt_buf, salt_bufs[SALT_POS].salt_len);
+
+  for (u32 i = 0, j = 1; i < 8; i += 8, j += 1)
+  {
+    sha512_hmac_ctx_t sha512_hmac_ctx2 = sha512_hmac_ctx;
+
+    u32 w0[4];
+    u32 w1[4];
+    u32 w2[4];
+    u32 w3[4];
+    u32 w4[4];
+    u32 w5[4];
+    u32 w6[4];
+    u32 w7[4];
+
+    w0[0] = j;
+    w0[1] = 0;
+    w0[2] = 0;
+    w0[3] = 0;
+    w1[0] = 0;
+    w1[1] = 0;
+    w1[2] = 0;
+    w1[3] = 0;
+    w2[0] = 0;
+    w2[1] = 0;
+    w2[2] = 0;
+    w2[3] = 0;
+    w3[0] = 0;
+    w3[1] = 0;
+    w3[2] = 0;
+    w3[3] = 0;
+    w4[0] = 0;
+    w4[1] = 0;
+    w4[2] = 0;
+    w4[3] = 0;
+    w5[0] = 0;
+    w5[1] = 0;
+    w5[2] = 0;
+    w5[3] = 0;
+    w6[0] = 0;
+    w6[1] = 0;
+    w6[2] = 0;
+    w6[3] = 0;
+    w7[0] = 0;
+    w7[1] = 0;
+    w7[2] = 0;
+    w7[3] = 0;
+
+    sha512_hmac_update_128 (&sha512_hmac_ctx2, w0, w1, w2, w3, w4, w5, w6, w7, 4);
+
+    sha512_hmac_final (&sha512_hmac_ctx2);
+
+    tmps[gid].dgst[i + 0] = sha512_hmac_ctx2.opad.h[0];
+    tmps[gid].dgst[i + 1] = sha512_hmac_ctx2.opad.h[1];
+    tmps[gid].dgst[i + 2] = sha512_hmac_ctx2.opad.h[2];
+    tmps[gid].dgst[i + 3] = sha512_hmac_ctx2.opad.h[3];
+    tmps[gid].dgst[i + 4] = sha512_hmac_ctx2.opad.h[4];
+    tmps[gid].dgst[i + 5] = sha512_hmac_ctx2.opad.h[5];
+    tmps[gid].dgst[i + 6] = sha512_hmac_ctx2.opad.h[6];
+    tmps[gid].dgst[i + 7] = sha512_hmac_ctx2.opad.h[7];
+
+    tmps[gid].out[i + 0] = tmps[gid].dgst[i + 0];
+    tmps[gid].out[i + 1] = tmps[gid].dgst[i + 1];
+    tmps[gid].out[i + 2] = tmps[gid].dgst[i + 2];
+    tmps[gid].out[i + 3] = tmps[gid].dgst[i + 3];
+    tmps[gid].out[i + 4] = tmps[gid].dgst[i + 4];
+    tmps[gid].out[i + 5] = tmps[gid].dgst[i + 5];
+    tmps[gid].out[i + 6] = tmps[gid].dgst[i + 6];
+    tmps[gid].out[i + 7] = tmps[gid].dgst[i + 7];
+  }
+}
+
+KERNEL_FQ void m24630_loop (KERN_ATTR_TMPS_ESALT (sqlcipher_sha512_tmp_t, sqlcipher_t))
+{
+  const u64 gid = get_global_id (0);
+
+  if ((gid * VECT_SIZE) >= gid_max) return;
+
+  u64x ipad[8];
+  u64x opad[8];
+
+  ipad[0] = pack64v (tmps, ipad, gid, 0);
+  ipad[1] = pack64v (tmps, ipad, gid, 1);
+  ipad[2] = pack64v (tmps, ipad, gid, 2);
+  ipad[3] = pack64v (tmps, ipad, gid, 3);
+  ipad[4] = pack64v (tmps, ipad, gid, 4);
+  ipad[5] = pack64v (tmps, ipad, gid, 5);
+  ipad[6] = pack64v (tmps, ipad, gid, 6);
+  ipad[7] = pack64v (tmps, ipad, gid, 7);
+
+  opad[0] = pack64v (tmps, opad, gid, 0);
+  opad[1] = pack64v (tmps, opad, gid, 1);
+  opad[2] = pack64v (tmps, opad, gid, 2);
+  opad[3] = pack64v (tmps, opad, gid, 3);
+  opad[4] = pack64v (tmps, opad, gid, 4);
+  opad[5] = pack64v (tmps, opad, gid, 5);
+  opad[6] = pack64v (tmps, opad, gid, 6);
+  opad[7] = pack64v (tmps, opad, gid, 7);
+
+  for (u32 i = 0; i < 8; i += 8)
+  {
+    u64x dgst[8];
+    u64x out[8];
+
+    dgst[0] = pack64v (tmps, dgst, gid, i + 0);
+    dgst[1] = pack64v (tmps, dgst, gid, i + 1);
+    dgst[2] = pack64v (tmps, dgst, gid, i + 2);
+    dgst[3] = pack64v (tmps, dgst, gid, i + 3);
+    dgst[4] = pack64v (tmps, dgst, gid, i + 4);
+    dgst[5] = pack64v (tmps, dgst, gid, i + 5);
+    dgst[6] = pack64v (tmps, dgst, gid, i + 6);
+    dgst[7] = pack64v (tmps, dgst, gid, i + 7);
+
+    out[0] = pack64v (tmps, out, gid, i + 0);
+    out[1] = pack64v (tmps, out, gid, i + 1);
+    out[2] = pack64v (tmps, out, gid, i + 2);
+    out[3] = pack64v (tmps, out, gid, i + 3);
+    out[4] = pack64v (tmps, out, gid, i + 4);
+    out[5] = pack64v (tmps, out, gid, i + 5);
+    out[6] = pack64v (tmps, out, gid, i + 6);
+    out[7] = pack64v (tmps, out, gid, i + 7);
+
+    for (u32 j = 0; j < loop_cnt; j++)
+    {
+      u32x w0[4];
+      u32x w1[4];
+      u32x w2[4];
+      u32x w3[4];
+      u32x w4[4];
+      u32x w5[4];
+      u32x w6[4];
+      u32x w7[4];
+
+      w0[0] = h32_from_64 (dgst[0]);
+      w0[1] = l32_from_64 (dgst[0]);
+      w0[2] = h32_from_64 (dgst[1]);
+      w0[3] = l32_from_64 (dgst[1]);
+      w1[0] = h32_from_64 (dgst[2]);
+      w1[1] = l32_from_64 (dgst[2]);
+      w1[2] = h32_from_64 (dgst[3]);
+      w1[3] = l32_from_64 (dgst[3]);
+      w2[0] = h32_from_64 (dgst[4]);
+      w2[1] = l32_from_64 (dgst[4]);
+      w2[2] = h32_from_64 (dgst[5]);
+      w2[3] = l32_from_64 (dgst[5]);
+      w3[0] = h32_from_64 (dgst[6]);
+      w3[1] = l32_from_64 (dgst[6]);
+      w3[2] = h32_from_64 (dgst[7]);
+      w3[3] = l32_from_64 (dgst[7]);
+      w4[0] = 0x80000000;
+      w4[1] = 0;
+      w4[2] = 0;
+      w4[3] = 0;
+      w5[0] = 0;
+      w5[1] = 0;
+      w5[2] = 0;
+      w5[3] = 0;
+      w6[0] = 0;
+      w6[1] = 0;
+      w6[2] = 0;
+      w6[3] = 0;
+      w7[0] = 0;
+      w7[1] = 0;
+      w7[2] = 0;
+      w7[3] = (128 + 64) * 8;
+
+      hmac_sha512_run_V (w0, w1, w2, w3, w4, w5, w6, w7, ipad, opad, dgst);
+
+      out[0] ^= dgst[0];
+      out[1] ^= dgst[1];
+      out[2] ^= dgst[2];
+      out[3] ^= dgst[3];
+      out[4] ^= dgst[4];
+      out[5] ^= dgst[5];
+      out[6] ^= dgst[6];
+      out[7] ^= dgst[7];
+    }
+
+    unpack64v (tmps, dgst, gid, i + 0, dgst[0]);
+    unpack64v (tmps, dgst, gid, i + 1, dgst[1]);
+    unpack64v (tmps, dgst, gid, i + 2, dgst[2]);
+    unpack64v (tmps, dgst, gid, i + 3, dgst[3]);
+    unpack64v (tmps, dgst, gid, i + 4, dgst[4]);
+    unpack64v (tmps, dgst, gid, i + 5, dgst[5]);
+    unpack64v (tmps, dgst, gid, i + 6, dgst[6]);
+    unpack64v (tmps, dgst, gid, i + 7, dgst[7]);
+
+    unpack64v (tmps, out, gid, i + 0, out[0]);
+    unpack64v (tmps, out, gid, i + 1, out[1]);
+    unpack64v (tmps, out, gid, i + 2, out[2]);
+    unpack64v (tmps, out, gid, i + 3, out[3]);
+    unpack64v (tmps, out, gid, i + 4, out[4]);
+    unpack64v (tmps, out, gid, i + 5, out[5]);
+    unpack64v (tmps, out, gid, i + 6, out[6]);
+    unpack64v (tmps, out, gid, i + 7, out[7]);
+  }
+}
+
+KERNEL_FQ void m24630_comp (KERN_ATTR_TMPS_ESALT (sqlcipher_sha512_tmp_t, sqlcipher_t))
+{
+  const u64 gid = get_global_id (0);
+  const u64 lid = get_local_id (0);
+  const u64 lsz = get_local_size (0);
+
+  /**
+   * aes shared
+   */
+
+  #ifdef REAL_SHM
+
+  LOCAL_VK u32 s_td0[256];
+  LOCAL_VK u32 s_td1[256];
+  LOCAL_VK u32 s_td2[256];
+  LOCAL_VK u32 s_td3[256];
+  LOCAL_VK u32 s_td4[256];
+
+  LOCAL_VK u32 s_te0[256];
+  LOCAL_VK u32 s_te1[256];
+  LOCAL_VK u32 s_te2[256];
+  LOCAL_VK u32 s_te3[256];
+  LOCAL_VK u32 s_te4[256];
+
+  for (u32 i = lid; i < 256; i += lsz)
+  {
+    s_td0[i] = td0[i];
+    s_td1[i] = td1[i];
+    s_td2[i] = td2[i];
+    s_td3[i] = td3[i];
+    s_td4[i] = td4[i];
+
+    s_te0[i] = te0[i];
+    s_te1[i] = te1[i];
+    s_te2[i] = te2[i];
+    s_te3[i] = te3[i];
+    s_te4[i] = te4[i];
+  }
+
+  SYNC_THREADS ();
+
+  #else
+
+  CONSTANT_AS u32a *s_td0 = td0;
+  CONSTANT_AS u32a *s_td1 = td1;
+  CONSTANT_AS u32a *s_td2 = td2;
+  CONSTANT_AS u32a *s_td3 = td3;
+  CONSTANT_AS u32a *s_td4 = td4;
+
+  CONSTANT_AS u32a *s_te0 = te0;
+  CONSTANT_AS u32a *s_te1 = te1;
+  CONSTANT_AS u32a *s_te2 = te2;
+  CONSTANT_AS u32a *s_te3 = te3;
+  CONSTANT_AS u32a *s_te4 = te4;
+
+  #endif
+
+  if (gid >= gid_max) return;
+
+  u32 ukey[8];
+
+  ukey[0] = h32_from_64_S (tmps[gid].out[0]);
+  ukey[1] = l32_from_64_S (tmps[gid].out[0]);
+  ukey[2] = h32_from_64_S (tmps[gid].out[1]);
+  ukey[3] = l32_from_64_S (tmps[gid].out[1]);
+  ukey[4] = h32_from_64_S (tmps[gid].out[2]);
+  ukey[5] = l32_from_64_S (tmps[gid].out[2]);
+  ukey[6] = h32_from_64_S (tmps[gid].out[3]);
+  ukey[7] = l32_from_64_S (tmps[gid].out[3]);
+
+  u32 ks[60];
+
+  AES256_set_decrypt_key (ks, ukey, s_te0, s_te1, s_te2, s_te3, s_td0, s_td1, s_td2, s_td3);
+
+  // first check the padding
+
+  u32 iv_buf[4];
+
+  iv_buf[0] = esalt_bufs[DIGESTS_OFFSET].iv_buf[0];
+  iv_buf[1] = esalt_bufs[DIGESTS_OFFSET].iv_buf[1];
+  iv_buf[2] = esalt_bufs[DIGESTS_OFFSET].iv_buf[2];
+  iv_buf[3] = esalt_bufs[DIGESTS_OFFSET].iv_buf[3];
+
+  u32 enc[4];
+
+  enc[0] = esalt_bufs[DIGESTS_OFFSET].data_buf[0];
+  enc[1] = esalt_bufs[DIGESTS_OFFSET].data_buf[1];
+  enc[2] = esalt_bufs[DIGESTS_OFFSET].data_buf[2];
+  enc[3] = esalt_bufs[DIGESTS_OFFSET].data_buf[3];
+
+  u32 dec[4];
+
+  aes256_decrypt (ks, enc, dec, s_td0, s_td1, s_td2, s_td3, s_td4);
+
+  dec[0] ^= iv_buf[0];
+  dec[1] ^= iv_buf[1];
+  dec[2] ^= iv_buf[2];
+  dec[3] ^= iv_buf[3];
+
+  if (dec[0] != 0) return;
+  if (dec[1] != 0) return;
+  if (dec[2] != 0) return;
+
+  const u32 r0 = esalt_bufs[DIGESTS_OFFSET].data_buf[0];
+  const u32 r1 = esalt_bufs[DIGESTS_OFFSET].data_buf[1];
+  const u32 r2 = esalt_bufs[DIGESTS_OFFSET].data_buf[2];
+  const u32 r3 = esalt_bufs[DIGESTS_OFFSET].data_buf[3];
+
+  #define il_pos 0
+
+  #ifdef KERNEL_STATIC
+  #include COMPARE_M
+  #endif
+}
diff --git a/OpenCL/m24700_a0-optimized.cl b/OpenCL/m24700_a0-optimized.cl
new file mode 100644
index 000000000..50bc227b3
--- /dev/null
+++ b/OpenCL/m24700_a0-optimized.cl
@@ -0,0 +1,496 @@
+/**
+ * Author......: See docs/credits.txt
+ * License.....: MIT
+ */
+
+#define NEW_SIMD_CODE
+
+#ifdef KERNEL_STATIC
+#include "inc_vendor.h"
+#include "inc_types.h"
+#include "inc_platform.cl"
+#include "inc_common.cl"
+#include "inc_rp_optimized.h"
+#include "inc_rp_optimized.cl"
+#include "inc_simd.cl"
+#include "inc_hash_md5.cl"
+#endif
+
+KERNEL_FQ void m24700_m04 (KERN_ATTR_RULES ())
+{
+  /**
+   * modifier
+   */
+
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  /**
+   * base
+   */
+
+  u32 pw_buf0[4];
+  u32 pw_buf1[4];
+
+  pw_buf0[0] = pws[gid].i[0];
+  pw_buf0[1] = pws[gid].i[1];
+  pw_buf0[2] = pws[gid].i[2];
+  pw_buf0[3] = pws[gid].i[3];
+  pw_buf1[0] = pws[gid].i[4];
+  pw_buf1[1] = pws[gid].i[5];
+  pw_buf1[2] = pws[gid].i[6];
+  pw_buf1[3] = pws[gid].i[7];
+
+  const u32 pw_len = pws[gid].pw_len & 63;
+
+  /**
+   * loop
+   */
+
+  for (u32 il_pos = 0; il_pos < il_cnt; il_pos += VECT_SIZE)
+  {
+    u32x w0[4] = { 0 };
+    u32x w1[4] = { 0 };
+    u32x w2[4] = { 0 };
+    u32x w3[4] = { 0 };
+
+    const u32x out_len = apply_rules_vect_optimized (pw_buf0, pw_buf1, pw_len, rules_buf, il_pos, w0, w1);
+
+    append_0x80_2x4_VV (w0, w1, out_len);
+
+    w3[2] = out_len * 8;
+    w3[3] = 0;
+
+    u32x a = MD5M_A;
+    u32x b = MD5M_B;
+    u32x c = MD5M_C;
+    u32x d = MD5M_D;
+
+    MD5_STEP (MD5_Fo, a, b, c, d, w0[0], MD5C00, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w0[1], MD5C01, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w0[2], MD5C02, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w0[3], MD5C03, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w1[0], MD5C04, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w1[1], MD5C05, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w1[2], MD5C06, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w1[3], MD5C07, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w2[0], MD5C08, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w2[1], MD5C09, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w2[2], MD5C0a, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w2[3], MD5C0b, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w3[0], MD5C0c, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w3[1], MD5C0d, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w3[2], MD5C0e, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w3[3], MD5C0f, MD5S03);
+
+    MD5_STEP (MD5_Go, a, b, c, d, w0[1], MD5C10, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w1[2], MD5C11, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w2[3], MD5C12, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w0[0], MD5C13, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w1[1], MD5C14, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w2[2], MD5C15, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w3[3], MD5C16, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w1[0], MD5C17, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w2[1], MD5C18, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w3[2], MD5C19, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w0[3], MD5C1a, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w2[0], MD5C1b, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w3[1], MD5C1c, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w0[2], MD5C1d, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w1[3], MD5C1e, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w3[0], MD5C1f, MD5S13);
+
+    u32x t;
+
+    MD5_STEP (MD5_H1, a, b, c, d, w1[1], MD5C20, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w2[0], MD5C21, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w2[3], MD5C22, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w3[2], MD5C23, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w0[1], MD5C24, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w1[0], MD5C25, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w1[3], MD5C26, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w2[2], MD5C27, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w3[1], MD5C28, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w0[0], MD5C29, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w0[3], MD5C2a, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w1[2], MD5C2b, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w2[1], MD5C2c, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w3[0], MD5C2d, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w3[3], MD5C2e, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w0[2], MD5C2f, MD5S23);
+
+    MD5_STEP (MD5_I , a, b, c, d, w0[0], MD5C30, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w1[3], MD5C31, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w3[2], MD5C32, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w1[1], MD5C33, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w3[0], MD5C34, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w0[3], MD5C35, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w2[2], MD5C36, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w0[1], MD5C37, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w2[0], MD5C38, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w3[3], MD5C39, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w1[2], MD5C3a, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w3[1], MD5C3b, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w1[0], MD5C3c, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w2[3], MD5C3d, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w0[2], MD5C3e, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w2[1], MD5C3f, MD5S33);
+
+    a += MD5M_A;
+    b += MD5M_B;
+    c += MD5M_C;
+    d += MD5M_D;
+
+    w0[0] = a;
+    w0[1] = b & 0xff; w0[1] |= 0x8000;
+    w0[2] = 0;
+    w0[3] = 0;
+    w1[0] = 0;
+    w1[1] = 0;
+    w1[2] = 0;
+    w1[3] = 0;
+    w2[0] = 0;
+    w2[1] = 0;
+    w2[2] = 0;
+    w2[3] = 0;
+    w3[0] = 0;
+    w3[1] = 0;
+    w3[2] = 5 * 8;
+    w3[3] = 0;
+
+    a = MD5M_A;
+    b = MD5M_B;
+    c = MD5M_C;
+    d = MD5M_D;
+
+    MD5_STEP (MD5_Fo, a, b, c, d, w0[0], MD5C00, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w0[1], MD5C01, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w0[2], MD5C02, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w0[3], MD5C03, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w1[0], MD5C04, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w1[1], MD5C05, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w1[2], MD5C06, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w1[3], MD5C07, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w2[0], MD5C08, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w2[1], MD5C09, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w2[2], MD5C0a, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w2[3], MD5C0b, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w3[0], MD5C0c, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w3[1], MD5C0d, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w3[2], MD5C0e, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w3[3], MD5C0f, MD5S03);
+
+    MD5_STEP (MD5_Go, a, b, c, d, w0[1], MD5C10, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w1[2], MD5C11, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w2[3], MD5C12, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w0[0], MD5C13, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w1[1], MD5C14, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w2[2], MD5C15, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w3[3], MD5C16, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w1[0], MD5C17, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w2[1], MD5C18, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w3[2], MD5C19, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w0[3], MD5C1a, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w2[0], MD5C1b, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w3[1], MD5C1c, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w0[2], MD5C1d, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w1[3], MD5C1e, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w3[0], MD5C1f, MD5S13);
+
+    MD5_STEP (MD5_H1, a, b, c, d, w1[1], MD5C20, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w2[0], MD5C21, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w2[3], MD5C22, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w3[2], MD5C23, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w0[1], MD5C24, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w1[0], MD5C25, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w1[3], MD5C26, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w2[2], MD5C27, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w3[1], MD5C28, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w0[0], MD5C29, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w0[3], MD5C2a, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w1[2], MD5C2b, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w2[1], MD5C2c, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w3[0], MD5C2d, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w3[3], MD5C2e, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w0[2], MD5C2f, MD5S23);
+
+    MD5_STEP (MD5_I , a, b, c, d, w0[0], MD5C30, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w1[3], MD5C31, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w3[2], MD5C32, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w1[1], MD5C33, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w3[0], MD5C34, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w0[3], MD5C35, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w2[2], MD5C36, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w0[1], MD5C37, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w2[0], MD5C38, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w3[3], MD5C39, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w1[2], MD5C3a, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w3[1], MD5C3b, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w1[0], MD5C3c, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w2[3], MD5C3d, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w0[2], MD5C3e, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w2[1], MD5C3f, MD5S33);
+
+    b &= 0xff;
+    c = 0;
+    d = 0;
+
+    COMPARE_M_SIMD (a, b, c, d);
+  }
+}
+
+KERNEL_FQ void m24700_m08 (KERN_ATTR_RULES ())
+{
+}
+
+KERNEL_FQ void m24700_m16 (KERN_ATTR_RULES ())
+{
+}
+
+KERNEL_FQ void m24700_s04 (KERN_ATTR_RULES ())
+{
+  /**
+   * modifier
+   */
+
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  /**
+   * base
+   */
+
+  u32 pw_buf0[4];
+  u32 pw_buf1[4];
+
+  pw_buf0[0] = pws[gid].i[0];
+  pw_buf0[1] = pws[gid].i[1];
+  pw_buf0[2] = pws[gid].i[2];
+  pw_buf0[3] = pws[gid].i[3];
+  pw_buf1[0] = pws[gid].i[4];
+  pw_buf1[1] = pws[gid].i[5];
+  pw_buf1[2] = pws[gid].i[6];
+  pw_buf1[3] = pws[gid].i[7];
+
+  const u32 pw_len = pws[gid].pw_len & 63;
+
+  /**
+   * digest
+   */
+
+  const u32 search[4] =
+  {
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R0],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R1],
+    0,
+    0
+  };
+
+  /**
+   * loop
+   */
+
+  for (u32 il_pos = 0; il_pos < il_cnt; il_pos += VECT_SIZE)
+  {
+    u32x w0[4] = { 0 };
+    u32x w1[4] = { 0 };
+    u32x w2[4] = { 0 };
+    u32x w3[4] = { 0 };
+
+    const u32x out_len = apply_rules_vect_optimized (pw_buf0, pw_buf1, pw_len, rules_buf, il_pos, w0, w1);
+
+    append_0x80_2x4_VV (w0, w1, out_len);
+
+    w3[2] = out_len * 8;
+    w3[3] = 0;
+
+    u32x a = MD5M_A;
+    u32x b = MD5M_B;
+    u32x c = MD5M_C;
+    u32x d = MD5M_D;
+
+    MD5_STEP (MD5_Fo, a, b, c, d, w0[0], MD5C00, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w0[1], MD5C01, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w0[2], MD5C02, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w0[3], MD5C03, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w1[0], MD5C04, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w1[1], MD5C05, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w1[2], MD5C06, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w1[3], MD5C07, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w2[0], MD5C08, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w2[1], MD5C09, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w2[2], MD5C0a, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w2[3], MD5C0b, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w3[0], MD5C0c, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w3[1], MD5C0d, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w3[2], MD5C0e, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w3[3], MD5C0f, MD5S03);
+
+    MD5_STEP (MD5_Go, a, b, c, d, w0[1], MD5C10, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w1[2], MD5C11, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w2[3], MD5C12, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w0[0], MD5C13, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w1[1], MD5C14, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w2[2], MD5C15, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w3[3], MD5C16, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w1[0], MD5C17, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w2[1], MD5C18, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w3[2], MD5C19, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w0[3], MD5C1a, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w2[0], MD5C1b, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w3[1], MD5C1c, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w0[2], MD5C1d, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w1[3], MD5C1e, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w3[0], MD5C1f, MD5S13);
+
+    u32x t;
+
+    MD5_STEP (MD5_H1, a, b, c, d, w1[1], MD5C20, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w2[0], MD5C21, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w2[3], MD5C22, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w3[2], MD5C23, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w0[1], MD5C24, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w1[0], MD5C25, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w1[3], MD5C26, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w2[2], MD5C27, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w3[1], MD5C28, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w0[0], MD5C29, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w0[3], MD5C2a, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w1[2], MD5C2b, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w2[1], MD5C2c, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w3[0], MD5C2d, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w3[3], MD5C2e, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w0[2], MD5C2f, MD5S23);
+
+    MD5_STEP (MD5_I , a, b, c, d, w0[0], MD5C30, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w1[3], MD5C31, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w3[2], MD5C32, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w1[1], MD5C33, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w3[0], MD5C34, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w0[3], MD5C35, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w2[2], MD5C36, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w0[1], MD5C37, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w2[0], MD5C38, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w3[3], MD5C39, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w1[2], MD5C3a, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w3[1], MD5C3b, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w1[0], MD5C3c, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w2[3], MD5C3d, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w0[2], MD5C3e, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w2[1], MD5C3f, MD5S33);
+
+    a += MD5M_A;
+    b += MD5M_B;
+    c += MD5M_C;
+    d += MD5M_D;
+
+    w0[0] = a;
+    w0[1] = b & 0xff; w0[1] |= 0x8000;
+    w0[2] = 0;
+    w0[3] = 0;
+    w1[0] = 0;
+    w1[1] = 0;
+    w1[2] = 0;
+    w1[3] = 0;
+    w2[0] = 0;
+    w2[1] = 0;
+    w2[2] = 0;
+    w2[3] = 0;
+    w3[0] = 0;
+    w3[1] = 0;
+    w3[2] = 5 * 8;
+    w3[3] = 0;
+
+    a = MD5M_A;
+    b = MD5M_B;
+    c = MD5M_C;
+    d = MD5M_D;
+
+    MD5_STEP (MD5_Fo, a, b, c, d, w0[0], MD5C00, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w0[1], MD5C01, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w0[2], MD5C02, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w0[3], MD5C03, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w1[0], MD5C04, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w1[1], MD5C05, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w1[2], MD5C06, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w1[3], MD5C07, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w2[0], MD5C08, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w2[1], MD5C09, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w2[2], MD5C0a, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w2[3], MD5C0b, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w3[0], MD5C0c, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w3[1], MD5C0d, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w3[2], MD5C0e, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w3[3], MD5C0f, MD5S03);
+
+    MD5_STEP (MD5_Go, a, b, c, d, w0[1], MD5C10, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w1[2], MD5C11, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w2[3], MD5C12, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w0[0], MD5C13, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w1[1], MD5C14, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w2[2], MD5C15, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w3[3], MD5C16, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w1[0], MD5C17, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w2[1], MD5C18, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w3[2], MD5C19, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w0[3], MD5C1a, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w2[0], MD5C1b, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w3[1], MD5C1c, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w0[2], MD5C1d, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w1[3], MD5C1e, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w3[0], MD5C1f, MD5S13);
+
+    MD5_STEP (MD5_H1, a, b, c, d, w1[1], MD5C20, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w2[0], MD5C21, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w2[3], MD5C22, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w3[2], MD5C23, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w0[1], MD5C24, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w1[0], MD5C25, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w1[3], MD5C26, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w2[2], MD5C27, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w3[1], MD5C28, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w0[0], MD5C29, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w0[3], MD5C2a, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w1[2], MD5C2b, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w2[1], MD5C2c, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w3[0], MD5C2d, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w3[3], MD5C2e, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w0[2], MD5C2f, MD5S23);
+
+    MD5_STEP (MD5_I , a, b, c, d, w0[0], MD5C30, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w1[3], MD5C31, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w3[2], MD5C32, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w1[1], MD5C33, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w3[0], MD5C34, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w0[3], MD5C35, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w2[2], MD5C36, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w0[1], MD5C37, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w2[0], MD5C38, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w3[3], MD5C39, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w1[2], MD5C3a, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w3[1], MD5C3b, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w1[0], MD5C3c, MD5S30);
+
+    if (MATCHES_NONE_VS (a, search[0])) continue;
+
+    MD5_STEP (MD5_I , d, a, b, c, w2[3], MD5C3d, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w0[2], MD5C3e, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w2[1], MD5C3f, MD5S33);
+
+    b &= 0xff;
+    c = 0;
+    d = 0;
+
+    COMPARE_S_SIMD (a, b, c, d);
+  }
+}
+
+KERNEL_FQ void m24700_s08 (KERN_ATTR_RULES ())
+{
+}
+
+KERNEL_FQ void m24700_s16 (KERN_ATTR_RULES ())
+{
+}
diff --git a/OpenCL/m24700_a0-pure.cl b/OpenCL/m24700_a0-pure.cl
new file mode 100644
index 000000000..796eca01d
--- /dev/null
+++ b/OpenCL/m24700_a0-pure.cl
@@ -0,0 +1,143 @@
+/**
+ * Author......: See docs/credits.txt
+ * License.....: MIT
+ */
+
+//#define NEW_SIMD_CODE
+
+#ifdef KERNEL_STATIC
+#include "inc_vendor.h"
+#include "inc_types.h"
+#include "inc_platform.cl"
+#include "inc_common.cl"
+#include "inc_rp.h"
+#include "inc_rp.cl"
+#include "inc_scalar.cl"
+#include "inc_hash_md5.cl"
+#endif
+
+KERNEL_FQ void m24700_mxx (KERN_ATTR_RULES ())
+{
+  /**
+   * modifier
+   */
+
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  /**
+   * base
+   */
+
+  COPY_PW (pws[gid]);
+
+  /**
+   * loop
+   */
+
+  for (u32 il_pos = 0; il_pos < il_cnt; il_pos++)
+  {
+    pw_t tmp = PASTE_PW;
+
+    tmp.pw_len = apply_rules (rules_buf[il_pos].cmds, tmp.i, tmp.pw_len);
+
+    md5_ctx_t ctx0;
+
+    md5_init (&ctx0);
+
+    md5_update (&ctx0, tmp.i, tmp.pw_len);
+
+    md5_final (&ctx0);
+
+    const u32 a = ctx0.h[0];
+    const u32 b = ctx0.h[1] & 0xff;
+
+    md5_ctx_t ctx;
+
+    md5_init (&ctx);
+
+    ctx.w0[0] = a;
+    ctx.w0[1] = b;
+
+    ctx.len = 5;
+
+    md5_final (&ctx);
+
+    const u32 r0 = ctx.h[DGST_R0];
+    const u32 r1 = ctx.h[DGST_R1] & 0xff;
+    const u32 r2 = 0;
+    const u32 r3 = 0;
+
+    COMPARE_M_SCALAR (r0, r1, r2, r3);
+  }
+}
+
+KERNEL_FQ void m24700_sxx (KERN_ATTR_RULES ())
+{
+  /**
+   * modifier
+   */
+
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  /**
+   * digest
+   */
+
+  const u32 search[4] =
+  {
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R0],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R1],
+    0,
+    0
+  };
+
+  /**
+   * base
+   */
+
+  COPY_PW (pws[gid]);
+
+  /**
+   * loop
+   */
+
+  for (u32 il_pos = 0; il_pos < il_cnt; il_pos++)
+  {
+    pw_t tmp = PASTE_PW;
+
+    tmp.pw_len = apply_rules (rules_buf[il_pos].cmds, tmp.i, tmp.pw_len);
+
+    md5_ctx_t ctx0;
+
+    md5_init (&ctx0);
+
+    md5_update (&ctx0, tmp.i, tmp.pw_len);
+
+    md5_final (&ctx0);
+
+    const u32 a = ctx0.h[0];
+    const u32 b = ctx0.h[1] & 0xff;
+
+    md5_ctx_t ctx;
+
+    md5_init (&ctx);
+
+    ctx.w0[0] = a;
+    ctx.w0[1] = b;
+
+    ctx.len = 5;
+
+    md5_final (&ctx);
+
+    const u32 r0 = ctx.h[DGST_R0];
+    const u32 r1 = ctx.h[DGST_R1] & 0xff;
+    const u32 r2 = 0;
+    const u32 r3 = 0;
+
+    COMPARE_S_SCALAR (r0, r1, r2, r3);
+  }
+}
diff --git a/OpenCL/m24700_a1-optimized.cl b/OpenCL/m24700_a1-optimized.cl
new file mode 100644
index 000000000..c9570e955
--- /dev/null
+++ b/OpenCL/m24700_a1-optimized.cl
@@ -0,0 +1,612 @@
+/**
+ * Author......: See docs/credits.txt
+ * License.....: MIT
+ */
+
+#define NEW_SIMD_CODE
+
+#ifdef KERNEL_STATIC
+#include "inc_vendor.h"
+#include "inc_types.h"
+#include "inc_platform.cl"
+#include "inc_common.cl"
+#include "inc_simd.cl"
+#include "inc_hash_md5.cl"
+#endif
+
+KERNEL_FQ void m24700_m04 (KERN_ATTR_BASIC ())
+{
+  /**
+   * modifier
+   */
+
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  /**
+   * base
+   */
+
+  u32 pw_buf0[4];
+  u32 pw_buf1[4];
+
+  pw_buf0[0] = pws[gid].i[0];
+  pw_buf0[1] = pws[gid].i[1];
+  pw_buf0[2] = pws[gid].i[2];
+  pw_buf0[3] = pws[gid].i[3];
+  pw_buf1[0] = pws[gid].i[4];
+  pw_buf1[1] = pws[gid].i[5];
+  pw_buf1[2] = pws[gid].i[6];
+  pw_buf1[3] = pws[gid].i[7];
+
+  const u32 pw_l_len = pws[gid].pw_len & 63;
+
+  /**
+   * loop
+   */
+
+  for (u32 il_pos = 0; il_pos < il_cnt; il_pos += VECT_SIZE)
+  {
+    const u32x pw_r_len = pwlenx_create_combt (combs_buf, il_pos) & 63;
+
+    const u32x pw_len = (pw_l_len + pw_r_len) & 63;
+
+    /**
+     * concat password candidate
+     */
+
+    u32x wordl0[4] = { 0 };
+    u32x wordl1[4] = { 0 };
+    u32x wordl2[4] = { 0 };
+    u32x wordl3[4] = { 0 };
+
+    wordl0[0] = pw_buf0[0];
+    wordl0[1] = pw_buf0[1];
+    wordl0[2] = pw_buf0[2];
+    wordl0[3] = pw_buf0[3];
+    wordl1[0] = pw_buf1[0];
+    wordl1[1] = pw_buf1[1];
+    wordl1[2] = pw_buf1[2];
+    wordl1[3] = pw_buf1[3];
+
+    u32x wordr0[4] = { 0 };
+    u32x wordr1[4] = { 0 };
+    u32x wordr2[4] = { 0 };
+    u32x wordr3[4] = { 0 };
+
+    wordr0[0] = ix_create_combt (combs_buf, il_pos, 0);
+    wordr0[1] = ix_create_combt (combs_buf, il_pos, 1);
+    wordr0[2] = ix_create_combt (combs_buf, il_pos, 2);
+    wordr0[3] = ix_create_combt (combs_buf, il_pos, 3);
+    wordr1[0] = ix_create_combt (combs_buf, il_pos, 4);
+    wordr1[1] = ix_create_combt (combs_buf, il_pos, 5);
+    wordr1[2] = ix_create_combt (combs_buf, il_pos, 6);
+    wordr1[3] = ix_create_combt (combs_buf, il_pos, 7);
+
+    if (combs_mode == COMBINATOR_MODE_BASE_LEFT)
+    {
+      switch_buffer_by_offset_le_VV (wordr0, wordr1, wordr2, wordr3, pw_l_len);
+    }
+    else
+    {
+      switch_buffer_by_offset_le_VV (wordl0, wordl1, wordl2, wordl3, pw_r_len);
+    }
+
+    u32x w0[4];
+    u32x w1[4];
+    u32x w2[4];
+    u32x w3[4];
+
+    w0[0] = wordl0[0] | wordr0[0];
+    w0[1] = wordl0[1] | wordr0[1];
+    w0[2] = wordl0[2] | wordr0[2];
+    w0[3] = wordl0[3] | wordr0[3];
+    w1[0] = wordl1[0] | wordr1[0];
+    w1[1] = wordl1[1] | wordr1[1];
+    w1[2] = wordl1[2] | wordr1[2];
+    w1[3] = wordl1[3] | wordr1[3];
+    w2[0] = wordl2[0] | wordr2[0];
+    w2[1] = wordl2[1] | wordr2[1];
+    w2[2] = wordl2[2] | wordr2[2];
+    w2[3] = wordl2[3] | wordr2[3];
+    w3[0] = wordl3[0] | wordr3[0];
+    w3[1] = wordl3[1] | wordr3[1];
+    w3[2] = pw_len * 8;
+    w3[3] = 0;
+
+    /**
+     * md5
+     */
+
+    u32x a = MD5M_A;
+    u32x b = MD5M_B;
+    u32x c = MD5M_C;
+    u32x d = MD5M_D;
+
+    MD5_STEP (MD5_Fo, a, b, c, d, w0[0], MD5C00, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w0[1], MD5C01, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w0[2], MD5C02, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w0[3], MD5C03, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w1[0], MD5C04, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w1[1], MD5C05, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w1[2], MD5C06, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w1[3], MD5C07, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w2[0], MD5C08, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w2[1], MD5C09, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w2[2], MD5C0a, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w2[3], MD5C0b, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w3[0], MD5C0c, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w3[1], MD5C0d, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w3[2], MD5C0e, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w3[3], MD5C0f, MD5S03);
+
+    MD5_STEP (MD5_Go, a, b, c, d, w0[1], MD5C10, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w1[2], MD5C11, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w2[3], MD5C12, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w0[0], MD5C13, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w1[1], MD5C14, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w2[2], MD5C15, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w3[3], MD5C16, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w1[0], MD5C17, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w2[1], MD5C18, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w3[2], MD5C19, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w0[3], MD5C1a, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w2[0], MD5C1b, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w3[1], MD5C1c, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w0[2], MD5C1d, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w1[3], MD5C1e, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w3[0], MD5C1f, MD5S13);
+
+    u32x t;
+
+    MD5_STEP (MD5_H1, a, b, c, d, w1[1], MD5C20, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w2[0], MD5C21, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w2[3], MD5C22, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w3[2], MD5C23, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w0[1], MD5C24, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w1[0], MD5C25, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w1[3], MD5C26, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w2[2], MD5C27, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w3[1], MD5C28, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w0[0], MD5C29, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w0[3], MD5C2a, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w1[2], MD5C2b, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w2[1], MD5C2c, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w3[0], MD5C2d, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w3[3], MD5C2e, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w0[2], MD5C2f, MD5S23);
+
+    MD5_STEP (MD5_I , a, b, c, d, w0[0], MD5C30, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w1[3], MD5C31, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w3[2], MD5C32, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w1[1], MD5C33, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w3[0], MD5C34, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w0[3], MD5C35, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w2[2], MD5C36, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w0[1], MD5C37, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w2[0], MD5C38, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w3[3], MD5C39, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w1[2], MD5C3a, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w3[1], MD5C3b, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w1[0], MD5C3c, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w2[3], MD5C3d, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w0[2], MD5C3e, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w2[1], MD5C3f, MD5S33);
+
+    a += MD5M_A;
+    b += MD5M_B;
+    c += MD5M_C;
+    d += MD5M_D;
+
+    w0[0] = a;
+    w0[1] = b & 0xff; w0[1] |= 0x8000;
+    w0[2] = 0;
+    w0[3] = 0;
+    w1[0] = 0;
+    w1[1] = 0;
+    w1[2] = 0;
+    w1[3] = 0;
+    w2[0] = 0;
+    w2[1] = 0;
+    w2[2] = 0;
+    w2[3] = 0;
+    w3[0] = 0;
+    w3[1] = 0;
+    w3[2] = 5 * 8;
+    w3[3] = 0;
+
+    a = MD5M_A;
+    b = MD5M_B;
+    c = MD5M_C;
+    d = MD5M_D;
+
+    MD5_STEP (MD5_Fo, a, b, c, d, w0[0], MD5C00, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w0[1], MD5C01, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w0[2], MD5C02, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w0[3], MD5C03, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w1[0], MD5C04, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w1[1], MD5C05, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w1[2], MD5C06, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w1[3], MD5C07, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w2[0], MD5C08, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w2[1], MD5C09, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w2[2], MD5C0a, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w2[3], MD5C0b, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w3[0], MD5C0c, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w3[1], MD5C0d, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w3[2], MD5C0e, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w3[3], MD5C0f, MD5S03);
+
+    MD5_STEP (MD5_Go, a, b, c, d, w0[1], MD5C10, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w1[2], MD5C11, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w2[3], MD5C12, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w0[0], MD5C13, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w1[1], MD5C14, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w2[2], MD5C15, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w3[3], MD5C16, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w1[0], MD5C17, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w2[1], MD5C18, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w3[2], MD5C19, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w0[3], MD5C1a, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w2[0], MD5C1b, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w3[1], MD5C1c, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w0[2], MD5C1d, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w1[3], MD5C1e, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w3[0], MD5C1f, MD5S13);
+
+    MD5_STEP (MD5_H1, a, b, c, d, w1[1], MD5C20, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w2[0], MD5C21, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w2[3], MD5C22, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w3[2], MD5C23, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w0[1], MD5C24, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w1[0], MD5C25, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w1[3], MD5C26, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w2[2], MD5C27, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w3[1], MD5C28, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w0[0], MD5C29, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w0[3], MD5C2a, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w1[2], MD5C2b, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w2[1], MD5C2c, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w3[0], MD5C2d, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w3[3], MD5C2e, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w0[2], MD5C2f, MD5S23);
+
+    MD5_STEP (MD5_I , a, b, c, d, w0[0], MD5C30, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w1[3], MD5C31, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w3[2], MD5C32, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w1[1], MD5C33, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w3[0], MD5C34, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w0[3], MD5C35, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w2[2], MD5C36, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w0[1], MD5C37, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w2[0], MD5C38, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w3[3], MD5C39, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w1[2], MD5C3a, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w3[1], MD5C3b, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w1[0], MD5C3c, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w2[3], MD5C3d, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w0[2], MD5C3e, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w2[1], MD5C3f, MD5S33);
+
+    b &= 0xff;
+    c = 0;
+    d = 0;
+
+    COMPARE_M_SIMD (a, b, c, d);
+  }
+}
+
+KERNEL_FQ void m24700_m08 (KERN_ATTR_BASIC ())
+{
+}
+
+KERNEL_FQ void m24700_m16 (KERN_ATTR_BASIC ())
+{
+}
+
+KERNEL_FQ void m24700_s04 (KERN_ATTR_BASIC ())
+{
+  /**
+   * modifier
+   */
+
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  /**
+   * base
+   */
+
+  u32 pw_buf0[4];
+  u32 pw_buf1[4];
+
+  pw_buf0[0] = pws[gid].i[0];
+  pw_buf0[1] = pws[gid].i[1];
+  pw_buf0[2] = pws[gid].i[2];
+  pw_buf0[3] = pws[gid].i[3];
+  pw_buf1[0] = pws[gid].i[4];
+  pw_buf1[1] = pws[gid].i[5];
+  pw_buf1[2] = pws[gid].i[6];
+  pw_buf1[3] = pws[gid].i[7];
+
+  const u32 pw_l_len = pws[gid].pw_len & 63;
+
+  /**
+   * digest
+   */
+
+  const u32 search[4] =
+  {
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R0],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R1],
+    0,
+    0
+  };
+
+  /**
+   * loop
+   */
+
+  for (u32 il_pos = 0; il_pos < il_cnt; il_pos += VECT_SIZE)
+  {
+    const u32x pw_r_len = pwlenx_create_combt (combs_buf, il_pos) & 63;
+
+    const u32x pw_len = (pw_l_len + pw_r_len) & 63;
+
+    /**
+     * concat password candidate
+     */
+
+    u32x wordl0[4] = { 0 };
+    u32x wordl1[4] = { 0 };
+    u32x wordl2[4] = { 0 };
+    u32x wordl3[4] = { 0 };
+
+    wordl0[0] = pw_buf0[0];
+    wordl0[1] = pw_buf0[1];
+    wordl0[2] = pw_buf0[2];
+    wordl0[3] = pw_buf0[3];
+    wordl1[0] = pw_buf1[0];
+    wordl1[1] = pw_buf1[1];
+    wordl1[2] = pw_buf1[2];
+    wordl1[3] = pw_buf1[3];
+
+    u32x wordr0[4] = { 0 };
+    u32x wordr1[4] = { 0 };
+    u32x wordr2[4] = { 0 };
+    u32x wordr3[4] = { 0 };
+
+    wordr0[0] = ix_create_combt (combs_buf, il_pos, 0);
+    wordr0[1] = ix_create_combt (combs_buf, il_pos, 1);
+    wordr0[2] = ix_create_combt (combs_buf, il_pos, 2);
+    wordr0[3] = ix_create_combt (combs_buf, il_pos, 3);
+    wordr1[0] = ix_create_combt (combs_buf, il_pos, 4);
+    wordr1[1] = ix_create_combt (combs_buf, il_pos, 5);
+    wordr1[2] = ix_create_combt (combs_buf, il_pos, 6);
+    wordr1[3] = ix_create_combt (combs_buf, il_pos, 7);
+
+    if (combs_mode == COMBINATOR_MODE_BASE_LEFT)
+    {
+      switch_buffer_by_offset_le_VV (wordr0, wordr1, wordr2, wordr3, pw_l_len);
+    }
+    else
+    {
+      switch_buffer_by_offset_le_VV (wordl0, wordl1, wordl2, wordl3, pw_r_len);
+    }
+
+    u32x w0[4];
+    u32x w1[4];
+    u32x w2[4];
+    u32x w3[4];
+
+    w0[0] = wordl0[0] | wordr0[0];
+    w0[1] = wordl0[1] | wordr0[1];
+    w0[2] = wordl0[2] | wordr0[2];
+    w0[3] = wordl0[3] | wordr0[3];
+    w1[0] = wordl1[0] | wordr1[0];
+    w1[1] = wordl1[1] | wordr1[1];
+    w1[2] = wordl1[2] | wordr1[2];
+    w1[3] = wordl1[3] | wordr1[3];
+    w2[0] = wordl2[0] | wordr2[0];
+    w2[1] = wordl2[1] | wordr2[1];
+    w2[2] = wordl2[2] | wordr2[2];
+    w2[3] = wordl2[3] | wordr2[3];
+    w3[0] = wordl3[0] | wordr3[0];
+    w3[1] = wordl3[1] | wordr3[1];
+    w3[2] = pw_len * 8;
+    w3[3] = 0;
+
+    /**
+     * md5
+     */
+
+    u32x a = MD5M_A;
+    u32x b = MD5M_B;
+    u32x c = MD5M_C;
+    u32x d = MD5M_D;
+
+    MD5_STEP (MD5_Fo, a, b, c, d, w0[0], MD5C00, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w0[1], MD5C01, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w0[2], MD5C02, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w0[3], MD5C03, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w1[0], MD5C04, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w1[1], MD5C05, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w1[2], MD5C06, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w1[3], MD5C07, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w2[0], MD5C08, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w2[1], MD5C09, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w2[2], MD5C0a, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w2[3], MD5C0b, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w3[0], MD5C0c, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w3[1], MD5C0d, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w3[2], MD5C0e, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w3[3], MD5C0f, MD5S03);
+
+    MD5_STEP (MD5_Go, a, b, c, d, w0[1], MD5C10, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w1[2], MD5C11, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w2[3], MD5C12, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w0[0], MD5C13, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w1[1], MD5C14, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w2[2], MD5C15, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w3[3], MD5C16, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w1[0], MD5C17, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w2[1], MD5C18, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w3[2], MD5C19, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w0[3], MD5C1a, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w2[0], MD5C1b, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w3[1], MD5C1c, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w0[2], MD5C1d, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w1[3], MD5C1e, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w3[0], MD5C1f, MD5S13);
+
+    u32x t;
+
+    MD5_STEP (MD5_H1, a, b, c, d, w1[1], MD5C20, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w2[0], MD5C21, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w2[3], MD5C22, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w3[2], MD5C23, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w0[1], MD5C24, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w1[0], MD5C25, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w1[3], MD5C26, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w2[2], MD5C27, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w3[1], MD5C28, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w0[0], MD5C29, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w0[3], MD5C2a, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w1[2], MD5C2b, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w2[1], MD5C2c, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w3[0], MD5C2d, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w3[3], MD5C2e, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w0[2], MD5C2f, MD5S23);
+
+    MD5_STEP (MD5_I , a, b, c, d, w0[0], MD5C30, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w1[3], MD5C31, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w3[2], MD5C32, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w1[1], MD5C33, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w3[0], MD5C34, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w0[3], MD5C35, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w2[2], MD5C36, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w0[1], MD5C37, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w2[0], MD5C38, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w3[3], MD5C39, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w1[2], MD5C3a, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w3[1], MD5C3b, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w1[0], MD5C3c, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w2[3], MD5C3d, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w0[2], MD5C3e, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w2[1], MD5C3f, MD5S33);
+
+    a += MD5M_A;
+    b += MD5M_B;
+    c += MD5M_C;
+    d += MD5M_D;
+
+    w0[0] = a;
+    w0[1] = b & 0xff; w0[1] |= 0x8000;
+    w0[2] = 0;
+    w0[3] = 0;
+    w1[0] = 0;
+    w1[1] = 0;
+    w1[2] = 0;
+    w1[3] = 0;
+    w2[0] = 0;
+    w2[1] = 0;
+    w2[2] = 0;
+    w2[3] = 0;
+    w3[0] = 0;
+    w3[1] = 0;
+    w3[2] = 5 * 8;
+    w3[3] = 0;
+
+    a = MD5M_A;
+    b = MD5M_B;
+    c = MD5M_C;
+    d = MD5M_D;
+
+    MD5_STEP (MD5_Fo, a, b, c, d, w0[0], MD5C00, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w0[1], MD5C01, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w0[2], MD5C02, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w0[3], MD5C03, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w1[0], MD5C04, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w1[1], MD5C05, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w1[2], MD5C06, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w1[3], MD5C07, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w2[0], MD5C08, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w2[1], MD5C09, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w2[2], MD5C0a, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w2[3], MD5C0b, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w3[0], MD5C0c, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w3[1], MD5C0d, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w3[2], MD5C0e, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w3[3], MD5C0f, MD5S03);
+
+    MD5_STEP (MD5_Go, a, b, c, d, w0[1], MD5C10, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w1[2], MD5C11, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w2[3], MD5C12, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w0[0], MD5C13, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w1[1], MD5C14, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w2[2], MD5C15, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w3[3], MD5C16, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w1[0], MD5C17, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w2[1], MD5C18, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w3[2], MD5C19, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w0[3], MD5C1a, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w2[0], MD5C1b, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w3[1], MD5C1c, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w0[2], MD5C1d, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w1[3], MD5C1e, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w3[0], MD5C1f, MD5S13);
+
+    MD5_STEP (MD5_H1, a, b, c, d, w1[1], MD5C20, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w2[0], MD5C21, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w2[3], MD5C22, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w3[2], MD5C23, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w0[1], MD5C24, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w1[0], MD5C25, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w1[3], MD5C26, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w2[2], MD5C27, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w3[1], MD5C28, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w0[0], MD5C29, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w0[3], MD5C2a, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w1[2], MD5C2b, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w2[1], MD5C2c, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w3[0], MD5C2d, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w3[3], MD5C2e, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w0[2], MD5C2f, MD5S23);
+
+    MD5_STEP (MD5_I , a, b, c, d, w0[0], MD5C30, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w1[3], MD5C31, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w3[2], MD5C32, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w1[1], MD5C33, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w3[0], MD5C34, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w0[3], MD5C35, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w2[2], MD5C36, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w0[1], MD5C37, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w2[0], MD5C38, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w3[3], MD5C39, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w1[2], MD5C3a, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w3[1], MD5C3b, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w1[0], MD5C3c, MD5S30);
+
+    if (MATCHES_NONE_VS (a, search[0])) continue;
+
+    MD5_STEP (MD5_I , d, a, b, c, w2[3], MD5C3d, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w0[2], MD5C3e, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w2[1], MD5C3f, MD5S33);
+
+    b &= 0xff;
+    c = 0;
+    d = 0;
+
+    COMPARE_S_SIMD (a, b, c, d);
+  }
+}
+
+KERNEL_FQ void m24700_s08 (KERN_ATTR_BASIC ())
+{
+}
+
+KERNEL_FQ void m24700_s16 (KERN_ATTR_BASIC ())
+{
+}
diff --git a/OpenCL/m24700_a1-pure.cl b/OpenCL/m24700_a1-pure.cl
new file mode 100644
index 000000000..3e2fbf662
--- /dev/null
+++ b/OpenCL/m24700_a1-pure.cl
@@ -0,0 +1,137 @@
+/**
+ * Author......: See docs/credits.txt
+ * License.....: MIT
+ */
+
+//#define NEW_SIMD_CODE
+
+#ifdef KERNEL_STATIC
+#include "inc_vendor.h"
+#include "inc_types.h"
+#include "inc_platform.cl"
+#include "inc_common.cl"
+#include "inc_scalar.cl"
+#include "inc_hash_md5.cl"
+#endif
+
+KERNEL_FQ void m24700_mxx (KERN_ATTR_BASIC ())
+{
+  /**
+   * modifier
+   */
+
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  /**
+   * base
+   */
+
+  md5_ctx_t ctx0;
+
+  md5_init (&ctx0);
+
+  md5_update_global (&ctx0, pws[gid].i, pws[gid].pw_len);
+
+  /**
+   * loop
+   */
+
+  for (u32 il_pos = 0; il_pos < il_cnt; il_pos++)
+  {
+    md5_ctx_t ctx1 = ctx0;
+
+    md5_update_global (&ctx1, combs_buf[il_pos].i, combs_buf[il_pos].pw_len);
+
+    md5_final (&ctx1);
+
+    const u32 a = ctx1.h[0];
+    const u32 b = ctx1.h[1] & 0xff;
+
+    md5_ctx_t ctx;
+
+    md5_init (&ctx);
+
+    ctx.w0[0] = a;
+    ctx.w0[1] = b;
+
+    ctx.len = 5;
+
+    md5_final (&ctx);
+
+    const u32 r0 = ctx.h[DGST_R0];
+    const u32 r1 = ctx.h[DGST_R1] & 0xff;
+    const u32 r2 = 0;
+    const u32 r3 = 0;
+
+    COMPARE_M_SCALAR (r0, r1, r2, r3);
+  }
+}
+
+KERNEL_FQ void m24700_sxx (KERN_ATTR_BASIC ())
+{
+  /**
+   * modifier
+   */
+
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  /**
+   * digest
+   */
+
+  const u32 search[4] =
+  {
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R0],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R1],
+    0,
+    0
+  };
+
+  /**
+   * base
+   */
+
+  md5_ctx_t ctx0;
+
+  md5_init (&ctx0);
+
+  md5_update_global (&ctx0, pws[gid].i, pws[gid].pw_len);
+
+  /**
+   * loop
+   */
+
+  for (u32 il_pos = 0; il_pos < il_cnt; il_pos++)
+  {
+    md5_ctx_t ctx1 = ctx0;
+
+    md5_update_global (&ctx1, combs_buf[il_pos].i, combs_buf[il_pos].pw_len);
+
+    md5_final (&ctx1);
+
+    const u32 a = ctx1.h[0];
+    const u32 b = ctx1.h[1] & 0xff;
+
+    md5_ctx_t ctx;
+
+    md5_init (&ctx);
+
+    ctx.w0[0] = a;
+    ctx.w0[1] = b;
+
+    ctx.len = 5;
+
+    md5_final (&ctx);
+
+    const u32 r0 = ctx.h[DGST_R0];
+    const u32 r1 = ctx.h[DGST_R1] & 0xff;
+    const u32 r2 = 0;
+    const u32 r3 = 0;
+
+    COMPARE_S_SCALAR (r0, r1, r2, r3);
+  }
+}
diff --git a/OpenCL/m24700_a3-optimized.cl b/OpenCL/m24700_a3-optimized.cl
new file mode 100644
index 000000000..0c5c99397
--- /dev/null
+++ b/OpenCL/m24700_a3-optimized.cl
@@ -0,0 +1,784 @@
+/**
+ * Author......: See docs/credits.txt
+ * License.....: MIT
+ */
+
+#define NEW_SIMD_CODE
+
+#ifdef KERNEL_STATIC
+#include "inc_vendor.h"
+#include "inc_types.h"
+#include "inc_platform.cl"
+#include "inc_common.cl"
+#include "inc_simd.cl"
+#include "inc_hash_md5.cl"
+#endif
+
+DECLSPEC void m24700m (u32 *w0, u32 *w1, u32 *w2, u32 *w3, const u32 pw_len, KERN_ATTR_BASIC ())
+{
+  /**
+   * modifier
+   */
+
+  const u64 gid = get_global_id (0);
+
+  /**
+   * loop
+   */
+
+  u32 w0l = w0[0];
+
+  for (u32 il_pos = 0; il_pos < il_cnt; il_pos += VECT_SIZE)
+  {
+    const u32x w0r = ix_create_bft (bfs_buf, il_pos);
+
+    const u32x w0lr = w0l | w0r;
+
+    u32x w0_t[4];
+    u32x w1_t[4];
+    u32x w2_t[4];
+    u32x w3_t[4];
+
+    w0_t[0] = w0lr;
+    w0_t[1] = w0[1];
+    w0_t[2] = w0[2];
+    w0_t[3] = w0[3];
+    w1_t[0] = w1[0];
+    w1_t[1] = w1[1];
+    w1_t[2] = w1[2];
+    w1_t[3] = w1[3];
+    w2_t[0] = w2[0];
+    w2_t[1] = w2[1];
+    w2_t[2] = w2[2];
+    w2_t[3] = w2[3];
+    w3_t[0] = w3[0];
+    w3_t[1] = w3[1];
+    w3_t[2] = w3[2];
+    w3_t[3] = w3[3];
+
+    /**
+     * md5
+     */
+
+    u32x a = MD5M_A;
+    u32x b = MD5M_B;
+    u32x c = MD5M_C;
+    u32x d = MD5M_D;
+
+    MD5_STEP (MD5_Fo, a, b, c, d, w0_t[0], MD5C00, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w0_t[1], MD5C01, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w0_t[2], MD5C02, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w0_t[3], MD5C03, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w1_t[0], MD5C04, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w1_t[1], MD5C05, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w1_t[2], MD5C06, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w1_t[3], MD5C07, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w2_t[0], MD5C08, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w2_t[1], MD5C09, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w2_t[2], MD5C0a, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w2_t[3], MD5C0b, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w3_t[0], MD5C0c, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w3_t[1], MD5C0d, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w3_t[2], MD5C0e, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w3_t[3], MD5C0f, MD5S03);
+
+    MD5_STEP (MD5_Go, a, b, c, d, w0_t[1], MD5C10, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w1_t[2], MD5C11, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w2_t[3], MD5C12, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w0_t[0], MD5C13, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w1_t[1], MD5C14, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w2_t[2], MD5C15, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w3_t[3], MD5C16, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w1_t[0], MD5C17, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w2_t[1], MD5C18, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w3_t[2], MD5C19, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w0_t[3], MD5C1a, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w2_t[0], MD5C1b, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w3_t[1], MD5C1c, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w0_t[2], MD5C1d, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w1_t[3], MD5C1e, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w3_t[0], MD5C1f, MD5S13);
+
+    u32x t;
+
+    MD5_STEP (MD5_H1, a, b, c, d, w1_t[1], MD5C20, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w2_t[0], MD5C21, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w2_t[3], MD5C22, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w3_t[2], MD5C23, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w0_t[1], MD5C24, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w1_t[0], MD5C25, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w1_t[3], MD5C26, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w2_t[2], MD5C27, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w3_t[1], MD5C28, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w0_t[0], MD5C29, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w0_t[3], MD5C2a, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w1_t[2], MD5C2b, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w2_t[1], MD5C2c, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w3_t[0], MD5C2d, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w3_t[3], MD5C2e, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w0_t[2], MD5C2f, MD5S23);
+
+    MD5_STEP (MD5_I , a, b, c, d, w0_t[0], MD5C30, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w1_t[3], MD5C31, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w3_t[2], MD5C32, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w1_t[1], MD5C33, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w3_t[0], MD5C34, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w0_t[3], MD5C35, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w2_t[2], MD5C36, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w0_t[1], MD5C37, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w2_t[0], MD5C38, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w3_t[3], MD5C39, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w1_t[2], MD5C3a, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w3_t[1], MD5C3b, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w1_t[0], MD5C3c, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w2_t[3], MD5C3d, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w0_t[2], MD5C3e, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w2_t[1], MD5C3f, MD5S33);
+
+    a += MD5M_A;
+    b += MD5M_B;
+    c += MD5M_C;
+    d += MD5M_D;
+
+    w0_t[0] = a;
+    w0_t[1] = b & 0xff; w0_t[1] |= 0x8000;
+    w0_t[2] = 0;
+    w0_t[3] = 0;
+    w1_t[0] = 0;
+    w1_t[1] = 0;
+    w1_t[2] = 0;
+    w1_t[3] = 0;
+    w2_t[0] = 0;
+    w2_t[1] = 0;
+    w2_t[2] = 0;
+    w2_t[3] = 0;
+    w3_t[0] = 0;
+    w3_t[1] = 0;
+    w3_t[2] = 5 * 8;
+    w3_t[3] = 0;
+
+    a = MD5M_A;
+    b = MD5M_B;
+    c = MD5M_C;
+    d = MD5M_D;
+
+    MD5_STEP (MD5_Fo, a, b, c, d, w0_t[0], MD5C00, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w0_t[1], MD5C01, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w0_t[2], MD5C02, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w0_t[3], MD5C03, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w1_t[0], MD5C04, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w1_t[1], MD5C05, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w1_t[2], MD5C06, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w1_t[3], MD5C07, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w2_t[0], MD5C08, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w2_t[1], MD5C09, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w2_t[2], MD5C0a, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w2_t[3], MD5C0b, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w3_t[0], MD5C0c, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w3_t[1], MD5C0d, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w3_t[2], MD5C0e, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w3_t[3], MD5C0f, MD5S03);
+
+    MD5_STEP (MD5_Go, a, b, c, d, w0_t[1], MD5C10, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w1_t[2], MD5C11, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w2_t[3], MD5C12, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w0_t[0], MD5C13, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w1_t[1], MD5C14, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w2_t[2], MD5C15, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w3_t[3], MD5C16, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w1_t[0], MD5C17, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w2_t[1], MD5C18, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w3_t[2], MD5C19, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w0_t[3], MD5C1a, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w2_t[0], MD5C1b, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w3_t[1], MD5C1c, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w0_t[2], MD5C1d, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w1_t[3], MD5C1e, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w3_t[0], MD5C1f, MD5S13);
+
+    MD5_STEP (MD5_H1, a, b, c, d, w1_t[1], MD5C20, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w2_t[0], MD5C21, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w2_t[3], MD5C22, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w3_t[2], MD5C23, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w0_t[1], MD5C24, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w1_t[0], MD5C25, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w1_t[3], MD5C26, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w2_t[2], MD5C27, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w3_t[1], MD5C28, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w0_t[0], MD5C29, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w0_t[3], MD5C2a, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w1_t[2], MD5C2b, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w2_t[1], MD5C2c, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w3_t[0], MD5C2d, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w3_t[3], MD5C2e, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w0_t[2], MD5C2f, MD5S23);
+
+    MD5_STEP (MD5_I , a, b, c, d, w0_t[0], MD5C30, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w1_t[3], MD5C31, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w3_t[2], MD5C32, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w1_t[1], MD5C33, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w3_t[0], MD5C34, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w0_t[3], MD5C35, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w2_t[2], MD5C36, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w0_t[1], MD5C37, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w2_t[0], MD5C38, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w3_t[3], MD5C39, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w1_t[2], MD5C3a, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w3_t[1], MD5C3b, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w1_t[0], MD5C3c, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w2_t[3], MD5C3d, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w0_t[2], MD5C3e, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w2_t[1], MD5C3f, MD5S33);
+
+    b &= 0xff;
+    c = 0;
+    d = 0;
+
+    COMPARE_M_SIMD (a, b, c, d);
+  }
+}
+
+DECLSPEC void m24700s (u32 *w0, u32 *w1, u32 *w2, u32 *w3, const u32 pw_len, KERN_ATTR_BASIC ())
+{
+  /**
+   * modifier
+   */
+
+  const u64 gid = get_global_id (0);
+
+  /**
+   * digest
+   */
+
+  const u32 search[4] =
+  {
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R0],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R1],
+    0,
+    0
+  };
+
+  /**
+   * loop
+   */
+
+  u32 w0l = w0[0];
+
+  for (u32 il_pos = 0; il_pos < il_cnt; il_pos += VECT_SIZE)
+  {
+    const u32x w0r = ix_create_bft (bfs_buf, il_pos);
+
+    const u32x w0lr = w0l | w0r;
+
+    u32x w0_t[4];
+    u32x w1_t[4];
+    u32x w2_t[4];
+    u32x w3_t[4];
+
+    w0_t[0] = w0lr;
+    w0_t[1] = w0[1];
+    w0_t[2] = w0[2];
+    w0_t[3] = w0[3];
+    w1_t[0] = w1[0];
+    w1_t[1] = w1[1];
+    w1_t[2] = w1[2];
+    w1_t[3] = w1[3];
+    w2_t[0] = w2[0];
+    w2_t[1] = w2[1];
+    w2_t[2] = w2[2];
+    w2_t[3] = w2[3];
+    w3_t[0] = w3[0];
+    w3_t[1] = w3[1];
+    w3_t[2] = w3[2];
+    w3_t[3] = w3[3];
+
+    /**
+     * md5
+     */
+
+    u32x a = MD5M_A;
+    u32x b = MD5M_B;
+    u32x c = MD5M_C;
+    u32x d = MD5M_D;
+
+    MD5_STEP (MD5_Fo, a, b, c, d, w0_t[0], MD5C00, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w0_t[1], MD5C01, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w0_t[2], MD5C02, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w0_t[3], MD5C03, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w1_t[0], MD5C04, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w1_t[1], MD5C05, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w1_t[2], MD5C06, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w1_t[3], MD5C07, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w2_t[0], MD5C08, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w2_t[1], MD5C09, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w2_t[2], MD5C0a, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w2_t[3], MD5C0b, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w3_t[0], MD5C0c, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w3_t[1], MD5C0d, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w3_t[2], MD5C0e, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w3_t[3], MD5C0f, MD5S03);
+
+    MD5_STEP (MD5_Go, a, b, c, d, w0_t[1], MD5C10, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w1_t[2], MD5C11, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w2_t[3], MD5C12, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w0_t[0], MD5C13, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w1_t[1], MD5C14, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w2_t[2], MD5C15, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w3_t[3], MD5C16, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w1_t[0], MD5C17, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w2_t[1], MD5C18, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w3_t[2], MD5C19, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w0_t[3], MD5C1a, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w2_t[0], MD5C1b, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w3_t[1], MD5C1c, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w0_t[2], MD5C1d, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w1_t[3], MD5C1e, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w3_t[0], MD5C1f, MD5S13);
+
+    u32x t;
+
+    MD5_STEP (MD5_H1, a, b, c, d, w1_t[1], MD5C20, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w2_t[0], MD5C21, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w2_t[3], MD5C22, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w3_t[2], MD5C23, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w0_t[1], MD5C24, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w1_t[0], MD5C25, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w1_t[3], MD5C26, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w2_t[2], MD5C27, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w3_t[1], MD5C28, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w0_t[0], MD5C29, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w0_t[3], MD5C2a, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w1_t[2], MD5C2b, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w2_t[1], MD5C2c, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w3_t[0], MD5C2d, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w3_t[3], MD5C2e, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w0_t[2], MD5C2f, MD5S23);
+
+    MD5_STEP (MD5_I , a, b, c, d, w0_t[0], MD5C30, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w1_t[3], MD5C31, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w3_t[2], MD5C32, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w1_t[1], MD5C33, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w3_t[0], MD5C34, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w0_t[3], MD5C35, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w2_t[2], MD5C36, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w0_t[1], MD5C37, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w2_t[0], MD5C38, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w3_t[3], MD5C39, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w1_t[2], MD5C3a, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w3_t[1], MD5C3b, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w1_t[0], MD5C3c, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w2_t[3], MD5C3d, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w0_t[2], MD5C3e, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w2_t[1], MD5C3f, MD5S33);
+
+    a += MD5M_A;
+    b += MD5M_B;
+    c += MD5M_C;
+    d += MD5M_D;
+
+    w0_t[0] = a;
+    w0_t[1] = b & 0xff; w0_t[1] |= 0x8000;
+    w0_t[2] = 0;
+    w0_t[3] = 0;
+    w1_t[0] = 0;
+    w1_t[1] = 0;
+    w1_t[2] = 0;
+    w1_t[3] = 0;
+    w2_t[0] = 0;
+    w2_t[1] = 0;
+    w2_t[2] = 0;
+    w2_t[3] = 0;
+    w3_t[0] = 0;
+    w3_t[1] = 0;
+    w3_t[2] = 5 * 8;
+    w3_t[3] = 0;
+
+    a = MD5M_A;
+    b = MD5M_B;
+    c = MD5M_C;
+    d = MD5M_D;
+
+    MD5_STEP (MD5_Fo, a, b, c, d, w0_t[0], MD5C00, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w0_t[1], MD5C01, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w0_t[2], MD5C02, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w0_t[3], MD5C03, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w1_t[0], MD5C04, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w1_t[1], MD5C05, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w1_t[2], MD5C06, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w1_t[3], MD5C07, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w2_t[0], MD5C08, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w2_t[1], MD5C09, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w2_t[2], MD5C0a, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w2_t[3], MD5C0b, MD5S03);
+    MD5_STEP (MD5_Fo, a, b, c, d, w3_t[0], MD5C0c, MD5S00);
+    MD5_STEP (MD5_Fo, d, a, b, c, w3_t[1], MD5C0d, MD5S01);
+    MD5_STEP (MD5_Fo, c, d, a, b, w3_t[2], MD5C0e, MD5S02);
+    MD5_STEP (MD5_Fo, b, c, d, a, w3_t[3], MD5C0f, MD5S03);
+
+    MD5_STEP (MD5_Go, a, b, c, d, w0_t[1], MD5C10, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w1_t[2], MD5C11, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w2_t[3], MD5C12, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w0_t[0], MD5C13, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w1_t[1], MD5C14, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w2_t[2], MD5C15, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w3_t[3], MD5C16, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w1_t[0], MD5C17, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w2_t[1], MD5C18, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w3_t[2], MD5C19, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w0_t[3], MD5C1a, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w2_t[0], MD5C1b, MD5S13);
+    MD5_STEP (MD5_Go, a, b, c, d, w3_t[1], MD5C1c, MD5S10);
+    MD5_STEP (MD5_Go, d, a, b, c, w0_t[2], MD5C1d, MD5S11);
+    MD5_STEP (MD5_Go, c, d, a, b, w1_t[3], MD5C1e, MD5S12);
+    MD5_STEP (MD5_Go, b, c, d, a, w3_t[0], MD5C1f, MD5S13);
+
+    MD5_STEP (MD5_H1, a, b, c, d, w1_t[1], MD5C20, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w2_t[0], MD5C21, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w2_t[3], MD5C22, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w3_t[2], MD5C23, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w0_t[1], MD5C24, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w1_t[0], MD5C25, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w1_t[3], MD5C26, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w2_t[2], MD5C27, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w3_t[1], MD5C28, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w0_t[0], MD5C29, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w0_t[3], MD5C2a, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w1_t[2], MD5C2b, MD5S23);
+    MD5_STEP (MD5_H1, a, b, c, d, w2_t[1], MD5C2c, MD5S20);
+    MD5_STEP (MD5_H2, d, a, b, c, w3_t[0], MD5C2d, MD5S21);
+    MD5_STEP (MD5_H1, c, d, a, b, w3_t[3], MD5C2e, MD5S22);
+    MD5_STEP (MD5_H2, b, c, d, a, w0_t[2], MD5C2f, MD5S23);
+
+    MD5_STEP (MD5_I , a, b, c, d, w0_t[0], MD5C30, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w1_t[3], MD5C31, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w3_t[2], MD5C32, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w1_t[1], MD5C33, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w3_t[0], MD5C34, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w0_t[3], MD5C35, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w2_t[2], MD5C36, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w0_t[1], MD5C37, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w2_t[0], MD5C38, MD5S30);
+    MD5_STEP (MD5_I , d, a, b, c, w3_t[3], MD5C39, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w1_t[2], MD5C3a, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w3_t[1], MD5C3b, MD5S33);
+    MD5_STEP (MD5_I , a, b, c, d, w1_t[0], MD5C3c, MD5S30);
+
+    if (MATCHES_NONE_VS (a, search[0])) continue;
+
+    MD5_STEP (MD5_I , d, a, b, c, w2_t[3], MD5C3d, MD5S31);
+    MD5_STEP (MD5_I , c, d, a, b, w0_t[2], MD5C3e, MD5S32);
+    MD5_STEP (MD5_I , b, c, d, a, w2_t[1], MD5C3f, MD5S33);
+
+    b &= 0xff;
+    c = 0;
+    d = 0;
+
+    COMPARE_S_SIMD (a, b, c, d);
+  }
+}
+
+KERNEL_FQ void m24700_m04 (KERN_ATTR_BASIC ())
+{
+  /**
+   * base
+   */
+
+  const u64 gid = get_global_id (0);
+
+  /**
+   * modifier
+   */
+
+  u32 w0[4];
+
+  w0[0] = pws[gid].i[ 0];
+  w0[1] = pws[gid].i[ 1];
+  w0[2] = pws[gid].i[ 2];
+  w0[3] = pws[gid].i[ 3];
+
+  u32 w1[4];
+
+  w1[0] = 0;
+  w1[1] = 0;
+  w1[2] = 0;
+  w1[3] = 0;
+
+  u32 w2[4];
+
+  w2[0] = 0;
+  w2[1] = 0;
+  w2[2] = 0;
+  w2[3] = 0;
+
+  u32 w3[4];
+
+  w3[0] = 0;
+  w3[1] = 0;
+  w3[2] = pws[gid].i[14];
+  w3[3] = 0;
+
+  const u32 pw_len = pws[gid].pw_len & 63;
+
+  if (gid >= gid_max) return;
+
+  /**
+   * main
+   */
+
+  m24700m (w0, w1, w2, w3, pw_len, pws, rules_buf, combs_buf, bfs_buf, tmps, hooks, bitmaps_buf_s1_a, bitmaps_buf_s1_b, bitmaps_buf_s1_c, bitmaps_buf_s1_d, bitmaps_buf_s2_a, bitmaps_buf_s2_b, bitmaps_buf_s2_c, bitmaps_buf_s2_d, plains_buf, digests_buf, hashes_shown, salt_bufs, esalt_bufs, d_return_buf, d_extra0_buf, d_extra1_buf, d_extra2_buf, d_extra3_buf, bitmap_mask, bitmap_shift1, bitmap_shift2, SALT_POS, loop_pos, loop_cnt, il_cnt, digests_cnt, DIGESTS_OFFSET, combs_mode, pws_pos, gid_max);
+}
+
+KERNEL_FQ void m24700_m08 (KERN_ATTR_BASIC ())
+{
+  /**
+   * base
+   */
+
+  const u64 gid = get_global_id (0);
+
+  /**
+   * modifier
+   */
+
+  u32 w0[4];
+
+  w0[0] = pws[gid].i[ 0];
+  w0[1] = pws[gid].i[ 1];
+  w0[2] = pws[gid].i[ 2];
+  w0[3] = pws[gid].i[ 3];
+
+  u32 w1[4];
+
+  w1[0] = pws[gid].i[ 4];
+  w1[1] = pws[gid].i[ 5];
+  w1[2] = pws[gid].i[ 6];
+  w1[3] = pws[gid].i[ 7];
+
+  u32 w2[4];
+
+  w2[0] = 0;
+  w2[1] = 0;
+  w2[2] = 0;
+  w2[3] = 0;
+
+  u32 w3[4];
+
+  w3[0] = 0;
+  w3[1] = 0;
+  w3[2] = pws[gid].i[14];
+  w3[3] = 0;
+
+  const u32 pw_len = pws[gid].pw_len & 63;
+
+  if (gid >= gid_max) return;
+
+  /**
+   * main
+   */
+
+  m24700m (w0, w1, w2, w3, pw_len, pws, rules_buf, combs_buf, bfs_buf, tmps, hooks, bitmaps_buf_s1_a, bitmaps_buf_s1_b, bitmaps_buf_s1_c, bitmaps_buf_s1_d, bitmaps_buf_s2_a, bitmaps_buf_s2_b, bitmaps_buf_s2_c, bitmaps_buf_s2_d, plains_buf, digests_buf, hashes_shown, salt_bufs, esalt_bufs, d_return_buf, d_extra0_buf, d_extra1_buf, d_extra2_buf, d_extra3_buf, bitmap_mask, bitmap_shift1, bitmap_shift2, SALT_POS, loop_pos, loop_cnt, il_cnt, digests_cnt, DIGESTS_OFFSET, combs_mode, pws_pos, gid_max);
+}
+
+KERNEL_FQ void m24700_m16 (KERN_ATTR_BASIC ())
+{
+  /**
+   * base
+   */
+
+  const u64 gid = get_global_id (0);
+
+  /**
+   * modifier
+   */
+
+  u32 w0[4];
+
+  w0[0] = pws[gid].i[ 0];
+  w0[1] = pws[gid].i[ 1];
+  w0[2] = pws[gid].i[ 2];
+  w0[3] = pws[gid].i[ 3];
+
+  u32 w1[4];
+
+  w1[0] = pws[gid].i[ 4];
+  w1[1] = pws[gid].i[ 5];
+  w1[2] = pws[gid].i[ 6];
+  w1[3] = pws[gid].i[ 7];
+
+  u32 w2[4];
+
+  w2[0] = pws[gid].i[ 8];
+  w2[1] = pws[gid].i[ 9];
+  w2[2] = pws[gid].i[10];
+  w2[3] = pws[gid].i[11];
+
+  u32 w3[4];
+
+  w3[0] = pws[gid].i[12];
+  w3[1] = pws[gid].i[13];
+  w3[2] = pws[gid].i[14];
+  w3[3] = pws[gid].i[15];
+
+  const u32 pw_len = pws[gid].pw_len & 63;
+
+  if (gid >= gid_max) return;
+
+  /**
+   * main
+   */
+
+  m24700m (w0, w1, w2, w3, pw_len, pws, rules_buf, combs_buf, bfs_buf, tmps, hooks, bitmaps_buf_s1_a, bitmaps_buf_s1_b, bitmaps_buf_s1_c, bitmaps_buf_s1_d, bitmaps_buf_s2_a, bitmaps_buf_s2_b, bitmaps_buf_s2_c, bitmaps_buf_s2_d, plains_buf, digests_buf, hashes_shown, salt_bufs, esalt_bufs, d_return_buf, d_extra0_buf, d_extra1_buf, d_extra2_buf, d_extra3_buf, bitmap_mask, bitmap_shift1, bitmap_shift2, SALT_POS, loop_pos, loop_cnt, il_cnt, digests_cnt, DIGESTS_OFFSET, combs_mode, pws_pos, gid_max);
+}
+
+KERNEL_FQ void m24700_s04 (KERN_ATTR_BASIC ())
+{
+  /**
+   * base
+   */
+
+  const u64 gid = get_global_id (0);
+
+  /**
+   * modifier
+   */
+
+  u32 w0[4];
+
+  w0[0] = pws[gid].i[ 0];
+  w0[1] = pws[gid].i[ 1];
+  w0[2] = pws[gid].i[ 2];
+  w0[3] = pws[gid].i[ 3];
+
+  u32 w1[4];
+
+  w1[0] = 0;
+  w1[1] = 0;
+  w1[2] = 0;
+  w1[3] = 0;
+
+  u32 w2[4];
+
+  w2[0] = 0;
+  w2[1] = 0;
+  w2[2] = 0;
+  w2[3] = 0;
+
+  u32 w3[4];
+
+  w3[0] = 0;
+  w3[1] = 0;
+  w3[2] = pws[gid].i[14];
+  w3[3] = 0;
+
+  const u32 pw_len = pws[gid].pw_len & 63;
+
+  if (gid >= gid_max) return;
+
+  /**
+   * main
+   */
+
+  m24700s (w0, w1, w2, w3, pw_len, pws, rules_buf, combs_buf, bfs_buf, tmps, hooks, bitmaps_buf_s1_a, bitmaps_buf_s1_b, bitmaps_buf_s1_c, bitmaps_buf_s1_d, bitmaps_buf_s2_a, bitmaps_buf_s2_b, bitmaps_buf_s2_c, bitmaps_buf_s2_d, plains_buf, digests_buf, hashes_shown, salt_bufs, esalt_bufs, d_return_buf, d_extra0_buf, d_extra1_buf, d_extra2_buf, d_extra3_buf, bitmap_mask, bitmap_shift1, bitmap_shift2, SALT_POS, loop_pos, loop_cnt, il_cnt, digests_cnt, DIGESTS_OFFSET, combs_mode, pws_pos, gid_max);
+}
+
+KERNEL_FQ void m24700_s08 (KERN_ATTR_BASIC ())
+{
+  /**
+   * base
+   */
+
+  const u64 gid = get_global_id (0);
+
+  /**
+   * modifier
+   */
+
+  u32 w0[4];
+
+  w0[0] = pws[gid].i[ 0];
+  w0[1] = pws[gid].i[ 1];
+  w0[2] = pws[gid].i[ 2];
+  w0[3] = pws[gid].i[ 3];
+
+  u32 w1[4];
+
+  w1[0] = pws[gid].i[ 4];
+  w1[1] = pws[gid].i[ 5];
+  w1[2] = pws[gid].i[ 6];
+  w1[3] = pws[gid].i[ 7];
+
+  u32 w2[4];
+
+  w2[0] = 0;
+  w2[1] = 0;
+  w2[2] = 0;
+  w2[3] = 0;
+
+  u32 w3[4];
+
+  w3[0] = 0;
+  w3[1] = 0;
+  w3[2] = pws[gid].i[14];
+  w3[3] = 0;
+
+  const u32 pw_len = pws[gid].pw_len & 63;
+
+  if (gid >= gid_max) return;
+
+  /**
+   * main
+   */
+
+  m24700s (w0, w1, w2, w3, pw_len, pws, rules_buf, combs_buf, bfs_buf, tmps, hooks, bitmaps_buf_s1_a, bitmaps_buf_s1_b, bitmaps_buf_s1_c, bitmaps_buf_s1_d, bitmaps_buf_s2_a, bitmaps_buf_s2_b, bitmaps_buf_s2_c, bitmaps_buf_s2_d, plains_buf, digests_buf, hashes_shown, salt_bufs, esalt_bufs, d_return_buf, d_extra0_buf, d_extra1_buf, d_extra2_buf, d_extra3_buf, bitmap_mask, bitmap_shift1, bitmap_shift2, SALT_POS, loop_pos, loop_cnt, il_cnt, digests_cnt, DIGESTS_OFFSET, combs_mode, pws_pos, gid_max);
+}
+
+KERNEL_FQ void m24700_s16 (KERN_ATTR_BASIC ())
+{
+  /**
+   * base
+   */
+
+  const u64 gid = get_global_id (0);
+
+  /**
+   * modifier
+   */
+
+  u32 w0[4];
+
+  w0[0] = pws[gid].i[ 0];
+  w0[1] = pws[gid].i[ 1];
+  w0[2] = pws[gid].i[ 2];
+  w0[3] = pws[gid].i[ 3];
+
+  u32 w1[4];
+
+  w1[0] = pws[gid].i[ 4];
+  w1[1] = pws[gid].i[ 5];
+  w1[2] = pws[gid].i[ 6];
+  w1[3] = pws[gid].i[ 7];
+
+  u32 w2[4];
+
+  w2[0] = pws[gid].i[ 8];
+  w2[1] = pws[gid].i[ 9];
+  w2[2] = pws[gid].i[10];
+  w2[3] = pws[gid].i[11];
+
+  u32 w3[4];
+
+  w3[0] = pws[gid].i[12];
+  w3[1] = pws[gid].i[13];
+  w3[2] = pws[gid].i[14];
+  w3[3] = pws[gid].i[15];
+
+  const u32 pw_len = pws[gid].pw_len & 63;
+
+  if (gid >= gid_max) return;
+
+  /**
+   * main
+   */
+
+  m24700s (w0, w1, w2, w3, pw_len, pws, rules_buf, combs_buf, bfs_buf, tmps, hooks, bitmaps_buf_s1_a, bitmaps_buf_s1_b, bitmaps_buf_s1_c, bitmaps_buf_s1_d, bitmaps_buf_s2_a, bitmaps_buf_s2_b, bitmaps_buf_s2_c, bitmaps_buf_s2_d, plains_buf, digests_buf, hashes_shown, salt_bufs, esalt_bufs, d_return_buf, d_extra0_buf, d_extra1_buf, d_extra2_buf, d_extra3_buf, bitmap_mask, bitmap_shift1, bitmap_shift2, SALT_POS, loop_pos, loop_cnt, il_cnt, digests_cnt, DIGESTS_OFFSET, combs_mode, pws_pos, gid_max);
+}
diff --git a/OpenCL/m24700_a3-pure.cl b/OpenCL/m24700_a3-pure.cl
new file mode 100644
index 000000000..9942c4415
--- /dev/null
+++ b/OpenCL/m24700_a3-pure.cl
@@ -0,0 +1,163 @@
+/**
+ * Author......: See docs/credits.txt
+ * License.....: MIT
+ */
+
+#define NEW_SIMD_CODE
+
+#ifdef KERNEL_STATIC
+#include "inc_vendor.h"
+#include "inc_types.h"
+#include "inc_platform.cl"
+#include "inc_common.cl"
+#include "inc_simd.cl"
+#include "inc_hash_md5.cl"
+#endif
+
+KERNEL_FQ void m24700_mxx (KERN_ATTR_VECTOR ())
+{
+  /**
+   * modifier
+   */
+
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  /**
+   * base
+   */
+
+  const u32 pw_len = pws[gid].pw_len;
+
+  u32x w[64] = { 0 };
+
+  for (u32 i = 0, idx = 0; i < pw_len; i += 4, idx += 1)
+  {
+    w[idx] = pws[gid].i[idx];
+  }
+
+  /**
+   * loop
+   */
+
+  u32x w0l = w[0];
+
+  for (u32 il_pos = 0; il_pos < il_cnt; il_pos += VECT_SIZE)
+  {
+    const u32x w0r = words_buf_r[il_pos / VECT_SIZE];
+
+    const u32x w0 = w0l | w0r;
+
+    w[0] = w0;
+
+    md5_ctx_vector_t ctx0;
+
+    md5_init_vector (&ctx0);
+
+    md5_update_vector (&ctx0, w, pw_len);
+
+    md5_final_vector (&ctx0);
+
+    const u32x a = ctx0.h[0];
+    const u32x b = ctx0.h[1] & 0xff;
+
+    md5_ctx_vector_t ctx;
+
+    md5_init_vector (&ctx);
+
+    ctx.w0[0] = a;
+    ctx.w0[1] = b;
+
+    ctx.len = 5;
+
+    md5_final_vector (&ctx);
+
+    const u32x r0 = ctx.h[DGST_R0];
+    const u32x r1 = ctx.h[DGST_R1] & 0xff;
+    const u32x r2 = 0;
+    const u32x r3 = 0;
+
+    COMPARE_M_SIMD (r0, r1, r2, r3);
+  }
+}
+
+KERNEL_FQ void m24700_sxx (KERN_ATTR_VECTOR ())
+{
+  /**
+   * modifier
+   */
+
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  /**
+   * digest
+   */
+
+  const u32 search[4] =
+  {
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R0],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R1],
+    0,
+    0
+  };
+
+  /**
+   * base
+   */
+
+  const u32 pw_len = pws[gid].pw_len;
+
+  u32x w[64] = { 0 };
+
+  for (u32 i = 0, idx = 0; i < pw_len; i += 4, idx += 1)
+  {
+    w[idx] = pws[gid].i[idx];
+  }
+
+  /**
+   * loop
+   */
+
+  u32x w0l = w[0];
+
+  for (u32 il_pos = 0; il_pos < il_cnt; il_pos += VECT_SIZE)
+  {
+    const u32x w0r = words_buf_r[il_pos / VECT_SIZE];
+
+    const u32x w0 = w0l | w0r;
+
+    w[0] = w0;
+
+    md5_ctx_vector_t ctx0;
+
+    md5_init_vector (&ctx0);
+
+    md5_update_vector (&ctx0, w, pw_len);
+
+    md5_final_vector (&ctx0);
+
+    const u32x a = ctx0.h[0];
+    const u32x b = ctx0.h[1] & 0xff;
+
+    md5_ctx_vector_t ctx;
+
+    md5_init_vector (&ctx);
+
+    ctx.w0[0] = a;
+    ctx.w0[1] = b;
+
+    ctx.len = 5;
+
+    md5_final_vector (&ctx);
+
+    const u32x r0 = ctx.h[DGST_R0];
+    const u32x r1 = ctx.h[DGST_R1] & 0xff;
+    const u32x r2 = 0;
+    const u32x r3 = 0;
+
+    COMPARE_S_SIMD (r0, r1, r2, r3);
+  }
+}
diff --git a/OpenCL/m24800_a0-optimized.cl b/OpenCL/m24800_a0-optimized.cl
new file mode 100644
index 000000000..9ef086f7c
--- /dev/null
+++ b/OpenCL/m24800_a0-optimized.cl
@@ -0,0 +1,362 @@
+/**
+ * Author......: See docs/credits.txt
+ * License.....: MIT
+ */
+
+#define NEW_SIMD_CODE
+
+#ifdef KERNEL_STATIC
+#include "inc_vendor.h"
+#include "inc_types.h"
+#include "inc_platform.cl"
+#include "inc_common.cl"
+#include "inc_rp_optimized.h"
+#include "inc_rp_optimized.cl"
+#include "inc_simd.cl"
+#include "inc_hash_sha1.cl"
+#endif
+
+DECLSPEC void hmac_sha1_pad (u32x *w0, u32x *w1, u32x *w2, u32x *w3, u32x *ipad, u32x *opad)
+{
+  w0[0] = w0[0] ^ 0x36363636;
+  w0[1] = w0[1] ^ 0x36363636;
+  w0[2] = w0[2] ^ 0x36363636;
+  w0[3] = w0[3] ^ 0x36363636;
+  w1[0] = w1[0] ^ 0x36363636;
+  w1[1] = w1[1] ^ 0x36363636;
+  w1[2] = w1[2] ^ 0x36363636;
+  w1[3] = w1[3] ^ 0x36363636;
+  w2[0] = w2[0] ^ 0x36363636;
+  w2[1] = w2[1] ^ 0x36363636;
+  w2[2] = w2[2] ^ 0x36363636;
+  w2[3] = w2[3] ^ 0x36363636;
+  w3[0] = w3[0] ^ 0x36363636;
+  w3[1] = w3[1] ^ 0x36363636;
+  w3[2] = w3[2] ^ 0x36363636;
+  w3[3] = w3[3] ^ 0x36363636;
+
+  ipad[0] = SHA1M_A;
+  ipad[1] = SHA1M_B;
+  ipad[2] = SHA1M_C;
+  ipad[3] = SHA1M_D;
+  ipad[4] = SHA1M_E;
+
+  sha1_transform_vector (w0, w1, w2, w3, ipad);
+
+  w0[0] = w0[0] ^ 0x6a6a6a6a;
+  w0[1] = w0[1] ^ 0x6a6a6a6a;
+  w0[2] = w0[2] ^ 0x6a6a6a6a;
+  w0[3] = w0[3] ^ 0x6a6a6a6a;
+  w1[0] = w1[0] ^ 0x6a6a6a6a;
+  w1[1] = w1[1] ^ 0x6a6a6a6a;
+  w1[2] = w1[2] ^ 0x6a6a6a6a;
+  w1[3] = w1[3] ^ 0x6a6a6a6a;
+  w2[0] = w2[0] ^ 0x6a6a6a6a;
+  w2[1] = w2[1] ^ 0x6a6a6a6a;
+  w2[2] = w2[2] ^ 0x6a6a6a6a;
+  w2[3] = w2[3] ^ 0x6a6a6a6a;
+  w3[0] = w3[0] ^ 0x6a6a6a6a;
+  w3[1] = w3[1] ^ 0x6a6a6a6a;
+  w3[2] = w3[2] ^ 0x6a6a6a6a;
+  w3[3] = w3[3] ^ 0x6a6a6a6a;
+
+  opad[0] = SHA1M_A;
+  opad[1] = SHA1M_B;
+  opad[2] = SHA1M_C;
+  opad[3] = SHA1M_D;
+  opad[4] = SHA1M_E;
+
+  sha1_transform_vector (w0, w1, w2, w3, opad);
+}
+
+DECLSPEC void hmac_sha1_run (u32x *w0, u32x *w1, u32x *w2, u32x *w3, u32x *ipad, u32x *opad, u32x *digest)
+{
+  digest[0] = ipad[0];
+  digest[1] = ipad[1];
+  digest[2] = ipad[2];
+  digest[3] = ipad[3];
+  digest[4] = ipad[4];
+
+  sha1_transform_vector (w0, w1, w2, w3, digest);
+
+  w0[0] = digest[0];
+  w0[1] = digest[1];
+  w0[2] = digest[2];
+  w0[3] = digest[3];
+  w1[0] = digest[4];
+  w1[1] = 0x80000000;
+  w1[2] = 0;
+  w1[3] = 0;
+  w2[0] = 0;
+  w2[1] = 0;
+  w2[2] = 0;
+  w2[3] = 0;
+  w3[0] = 0;
+  w3[1] = 0;
+  w3[2] = 0;
+  w3[3] = (64 + 20) * 8;
+
+  digest[0] = opad[0];
+  digest[1] = opad[1];
+  digest[2] = opad[2];
+  digest[3] = opad[3];
+  digest[4] = opad[4];
+
+  sha1_transform_vector (w0, w1, w2, w3, digest);
+}
+
+KERNEL_FQ void m24800_m04 (KERN_ATTR_RULES ())
+{
+  /**
+   * modifier
+   */
+
+  const u64 lid = get_local_id (0);
+
+  /**
+   * base
+   */
+
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  u32 pw_buf0[4];
+  u32 pw_buf1[4];
+
+  pw_buf0[0] = pws[gid].i[0];
+  pw_buf0[1] = pws[gid].i[1];
+  pw_buf0[2] = pws[gid].i[2];
+  pw_buf0[3] = pws[gid].i[3];
+  pw_buf1[0] = pws[gid].i[4];
+  pw_buf1[1] = pws[gid].i[5];
+  pw_buf1[2] = pws[gid].i[6];
+  pw_buf1[3] = pws[gid].i[7];
+
+  const u32 pw_len = pws[gid].pw_len & 63;
+
+  /**
+   * loop
+   */
+
+  for (u32 il_pos = 0; il_pos < il_cnt; il_pos += VECT_SIZE)
+  {
+    u32x w0[4] = { 0 };
+    u32x w1[4] = { 0 };
+    u32x w2[4] = { 0 };
+    u32x w3[4] = { 0 };
+
+    const u32x out_len = apply_rules_vect_optimized (pw_buf0, pw_buf1, pw_len, rules_buf, il_pos, w0, w1);
+
+    const u32x out_len2 = out_len * 2;
+
+    w0[0] = hc_swap32 (w0[0]);
+    w0[1] = hc_swap32 (w0[1]);
+    w0[2] = hc_swap32 (w0[2]);
+    w0[3] = hc_swap32 (w0[3]);
+    w1[0] = hc_swap32 (w1[0]);
+    w1[1] = hc_swap32 (w1[1]);
+    w1[2] = hc_swap32 (w1[2]);
+    w1[3] = hc_swap32 (w1[3]);
+
+    make_utf16beN (w1, w2, w3);
+    make_utf16beN (w0, w0, w1);
+
+    u32x x0_t[4];
+    u32x x1_t[4];
+    u32x x2_t[4];
+    u32x x3_t[4];
+
+    x0_t[0] = w0[0];
+    x0_t[1] = w0[1];
+    x0_t[2] = w0[2];
+    x0_t[3] = w0[3];
+    x1_t[0] = w1[0];
+    x1_t[1] = w1[1];
+    x1_t[2] = w1[2];
+    x1_t[3] = w1[3];
+    x2_t[0] = w2[0];
+    x2_t[1] = w2[1];
+    x2_t[2] = w2[2];
+    x2_t[3] = w2[3];
+    x3_t[0] = w3[0];
+    x3_t[1] = w3[1];
+    x3_t[2] = w3[2];
+    x3_t[3] = w3[3];
+
+    u32x ipad[5];
+    u32x opad[5];
+
+    hmac_sha1_pad (x0_t, x1_t, x2_t, x3_t, ipad, opad);
+
+    x0_t[0] = w0[0];
+    x0_t[1] = w0[1];
+    x0_t[2] = w0[2];
+    x0_t[3] = w0[3];
+    x1_t[0] = w1[0];
+    x1_t[1] = w1[1];
+    x1_t[2] = w1[2];
+    x1_t[3] = w1[3];
+    x2_t[0] = w2[0];
+    x2_t[1] = w2[1];
+    x2_t[2] = w2[2];
+    x2_t[3] = w2[3];
+    x3_t[0] = w3[0];
+    x3_t[1] = w3[1];
+    x3_t[2] = w3[2];
+    x3_t[3] = w3[3];
+
+    append_0x80_4x4_VV (x0_t, x1_t, x2_t, x3_t, out_len2 ^ 3);
+
+    x3_t[2] = 0;
+    x3_t[3] = (64 + out_len2) * 8;
+
+    u32x digest[5];
+
+    hmac_sha1_run (x0_t, x1_t, x2_t, x3_t, ipad, opad, digest);
+
+    COMPARE_M_SIMD (digest[3], digest[4], digest[2], digest[1]);
+  }
+}
+
+KERNEL_FQ void m24800_m08 (KERN_ATTR_RULES ())
+{
+}
+
+KERNEL_FQ void m24800_m16 (KERN_ATTR_RULES ())
+{
+}
+
+KERNEL_FQ void m24800_s04 (KERN_ATTR_RULES ())
+{
+  /**
+   * modifier
+   */
+
+  const u64 lid = get_local_id (0);
+
+  /**
+   * base
+   */
+
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  u32 pw_buf0[4];
+  u32 pw_buf1[4];
+
+  pw_buf0[0] = pws[gid].i[0];
+  pw_buf0[1] = pws[gid].i[1];
+  pw_buf0[2] = pws[gid].i[2];
+  pw_buf0[3] = pws[gid].i[3];
+  pw_buf1[0] = pws[gid].i[4];
+  pw_buf1[1] = pws[gid].i[5];
+  pw_buf1[2] = pws[gid].i[6];
+  pw_buf1[3] = pws[gid].i[7];
+
+  const u32 pw_len = pws[gid].pw_len & 63;
+
+  /**
+   * digest
+   */
+
+  const u32 search[4] =
+  {
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R0],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R1],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R2],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R3]
+  };
+
+  /**
+   * loop
+   */
+
+  for (u32 il_pos = 0; il_pos < il_cnt; il_pos += VECT_SIZE)
+  {
+    u32x w0[4] = { 0 };
+    u32x w1[4] = { 0 };
+    u32x w2[4] = { 0 };
+    u32x w3[4] = { 0 };
+
+    const u32x out_len = apply_rules_vect_optimized (pw_buf0, pw_buf1, pw_len, rules_buf, il_pos, w0, w1);
+
+    const u32x out_len2 = out_len * 2;
+
+    w0[0] = hc_swap32 (w0[0]);
+    w0[1] = hc_swap32 (w0[1]);
+    w0[2] = hc_swap32 (w0[2]);
+    w0[3] = hc_swap32 (w0[3]);
+    w1[0] = hc_swap32 (w1[0]);
+    w1[1] = hc_swap32 (w1[1]);
+    w1[2] = hc_swap32 (w1[2]);
+    w1[3] = hc_swap32 (w1[3]);
+
+    make_utf16beN (w1, w2, w3);
+    make_utf16beN (w0, w0, w1);
+
+    u32x x0_t[4];
+    u32x x1_t[4];
+    u32x x2_t[4];
+    u32x x3_t[4];
+
+    x0_t[0] = w0[0];
+    x0_t[1] = w0[1];
+    x0_t[2] = w0[2];
+    x0_t[3] = w0[3];
+    x1_t[0] = w1[0];
+    x1_t[1] = w1[1];
+    x1_t[2] = w1[2];
+    x1_t[3] = w1[3];
+    x2_t[0] = w2[0];
+    x2_t[1] = w2[1];
+    x2_t[2] = w2[2];
+    x2_t[3] = w2[3];
+    x3_t[0] = w3[0];
+    x3_t[1] = w3[1];
+    x3_t[2] = w3[2];
+    x3_t[3] = w3[3];
+
+    u32x ipad[5];
+    u32x opad[5];
+
+    hmac_sha1_pad (x0_t, x1_t, x2_t, x3_t, ipad, opad);
+
+    x0_t[0] = w0[0];
+    x0_t[1] = w0[1];
+    x0_t[2] = w0[2];
+    x0_t[3] = w0[3];
+    x1_t[0] = w1[0];
+    x1_t[1] = w1[1];
+    x1_t[2] = w1[2];
+    x1_t[3] = w1[3];
+    x2_t[0] = w2[0];
+    x2_t[1] = w2[1];
+    x2_t[2] = w2[2];
+    x2_t[3] = w2[3];
+    x3_t[0] = w3[0];
+    x3_t[1] = w3[1];
+    x3_t[2] = w3[2];
+    x3_t[3] = w3[3];
+
+    append_0x80_4x4_VV (x0_t, x1_t, x2_t, x3_t, out_len2 ^ 3);
+
+    x3_t[2] = 0;
+    x3_t[3] = (64 + out_len2) * 8;
+
+    u32x digest[5];
+
+    hmac_sha1_run (x0_t, x1_t, x2_t, x3_t, ipad, opad, digest);
+
+    COMPARE_S_SIMD (digest[3], digest[4], digest[2], digest[1]);
+  }
+}
+
+KERNEL_FQ void m24800_s08 (KERN_ATTR_RULES ())
+{
+}
+
+KERNEL_FQ void m24800_s16 (KERN_ATTR_RULES ())
+{
+}
diff --git a/OpenCL/m24800_a0-pure.cl b/OpenCL/m24800_a0-pure.cl
new file mode 100644
index 000000000..4140ed966
--- /dev/null
+++ b/OpenCL/m24800_a0-pure.cl
@@ -0,0 +1,147 @@
+/**
+ * Author......: See docs/credits.txt
+ * License.....: MIT
+ */
+
+//#define NEW_SIMD_CODE
+
+#ifdef KERNEL_STATIC
+#include "inc_vendor.h"
+#include "inc_types.h"
+#include "inc_platform.cl"
+#include "inc_common.cl"
+#include "inc_rp.h"
+#include "inc_rp.cl"
+#include "inc_scalar.cl"
+#include "inc_hash_sha1.cl"
+#endif
+
+KERNEL_FQ void m24800_mxx (KERN_ATTR_RULES ())
+{
+  /**
+   * modifier
+   */
+
+  const u64 lid = get_local_id (0);
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  /**
+   * base
+   */
+
+  COPY_PW (pws[gid]);
+
+  /**
+   * loop
+   */
+
+  for (u32 il_pos = 0; il_pos < il_cnt; il_pos++)
+  {
+    pw_t tmp = PASTE_PW;
+
+    tmp.pw_len = apply_rules (rules_buf[il_pos].cmds, tmp.i, tmp.pw_len);
+
+    // swap endian
+    for (u32 i = 0, idx = 0; i < tmp.pw_len; i += 4, idx += 1)
+    {
+      tmp.i[idx] = hc_swap32 (tmp.i[idx]);
+    }
+
+    u32 t[128] = { 0 };
+
+    // make it unicode.
+    for (u32 i = 0, idx = 0; idx < tmp.pw_len; i += 2, idx += 1)
+    {
+      make_utf16beN (&tmp.i[idx], &t[i], &t[i+1]);
+    }
+
+    // hash time
+    sha1_hmac_ctx_t ctx;
+
+    sha1_hmac_init (&ctx, t, tmp.pw_len * 2);
+
+    sha1_hmac_update (&ctx, t, tmp.pw_len * 2);
+
+    sha1_hmac_final (&ctx);
+
+    const u32 r0 = ctx.opad.h[DGST_R0];
+    const u32 r1 = ctx.opad.h[DGST_R1];
+    const u32 r2 = ctx.opad.h[DGST_R2];
+    const u32 r3 = ctx.opad.h[DGST_R3];
+
+    COMPARE_M_SCALAR (r0, r1, r2, r3);
+  }
+}
+
+KERNEL_FQ void m24800_sxx (KERN_ATTR_RULES ())
+{
+  /**
+   * modifier
+   */
+
+  const u64 lid = get_local_id (0);
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  /**
+   * digest
+   */
+
+  const u32 search[4] =
+  {
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R0],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R1],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R2],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R3]
+  };
+
+  /**
+   * base
+   */
+
+  COPY_PW (pws[gid]);
+
+  /**
+   * loop
+   */
+
+  for (u32 il_pos = 0; il_pos < il_cnt; il_pos++)
+  {
+    pw_t tmp = PASTE_PW;
+
+    tmp.pw_len = apply_rules (rules_buf[il_pos].cmds, tmp.i, tmp.pw_len);
+
+    // swap endian
+    for (u32 i = 0, idx = 0; i < tmp.pw_len; i += 4, idx += 1)
+    {
+      tmp.i[idx] = hc_swap32 (tmp.i[idx]);
+    }
+
+    u32 t[128] = { 0 };
+
+    // make it unicode.
+    for (u32 i = 0, idx = 0; idx < tmp.pw_len; i += 2, idx += 1)
+    {
+      make_utf16beN (&tmp.i[idx], &t[i], &t[i+1]);
+    }
+
+    // hash time
+    sha1_hmac_ctx_t ctx;
+
+    sha1_hmac_init (&ctx, t, tmp.pw_len * 2);
+
+    sha1_hmac_update (&ctx, t, tmp.pw_len * 2);
+
+    sha1_hmac_final (&ctx);
+
+    const u32 r0 = ctx.opad.h[DGST_R0];
+    const u32 r1 = ctx.opad.h[DGST_R1];
+    const u32 r2 = ctx.opad.h[DGST_R2];
+    const u32 r3 = ctx.opad.h[DGST_R3];
+
+    COMPARE_S_SCALAR (r0, r1, r2, r3);
+  }
+}
diff --git a/OpenCL/m24800_a1-optimized.cl b/OpenCL/m24800_a1-optimized.cl
new file mode 100644
index 000000000..02451900c
--- /dev/null
+++ b/OpenCL/m24800_a1-optimized.cl
@@ -0,0 +1,464 @@
+/**
+ * Author......: See docs/credits.txt
+ * License.....: MIT
+ */
+
+#define NEW_SIMD_CODE
+
+#ifdef KERNEL_STATIC
+#include "inc_vendor.h"
+#include "inc_types.h"
+#include "inc_platform.cl"
+#include "inc_common.cl"
+#include "inc_simd.cl"
+#include "inc_hash_sha1.cl"
+#endif
+
+DECLSPEC void hmac_sha1_pad (u32x *w0, u32x *w1, u32x *w2, u32x *w3, u32x *ipad, u32x *opad)
+{
+  w0[0] = w0[0] ^ 0x36363636;
+  w0[1] = w0[1] ^ 0x36363636;
+  w0[2] = w0[2] ^ 0x36363636;
+  w0[3] = w0[3] ^ 0x36363636;
+  w1[0] = w1[0] ^ 0x36363636;
+  w1[1] = w1[1] ^ 0x36363636;
+  w1[2] = w1[2] ^ 0x36363636;
+  w1[3] = w1[3] ^ 0x36363636;
+  w2[0] = w2[0] ^ 0x36363636;
+  w2[1] = w2[1] ^ 0x36363636;
+  w2[2] = w2[2] ^ 0x36363636;
+  w2[3] = w2[3] ^ 0x36363636;
+  w3[0] = w3[0] ^ 0x36363636;
+  w3[1] = w3[1] ^ 0x36363636;
+  w3[2] = w3[2] ^ 0x36363636;
+  w3[3] = w3[3] ^ 0x36363636;
+
+  ipad[0] = SHA1M_A;
+  ipad[1] = SHA1M_B;
+  ipad[2] = SHA1M_C;
+  ipad[3] = SHA1M_D;
+  ipad[4] = SHA1M_E;
+
+  sha1_transform_vector (w0, w1, w2, w3, ipad);
+
+  w0[0] = w0[0] ^ 0x6a6a6a6a;
+  w0[1] = w0[1] ^ 0x6a6a6a6a;
+  w0[2] = w0[2] ^ 0x6a6a6a6a;
+  w0[3] = w0[3] ^ 0x6a6a6a6a;
+  w1[0] = w1[0] ^ 0x6a6a6a6a;
+  w1[1] = w1[1] ^ 0x6a6a6a6a;
+  w1[2] = w1[2] ^ 0x6a6a6a6a;
+  w1[3] = w1[3] ^ 0x6a6a6a6a;
+  w2[0] = w2[0] ^ 0x6a6a6a6a;
+  w2[1] = w2[1] ^ 0x6a6a6a6a;
+  w2[2] = w2[2] ^ 0x6a6a6a6a;
+  w2[3] = w2[3] ^ 0x6a6a6a6a;
+  w3[0] = w3[0] ^ 0x6a6a6a6a;
+  w3[1] = w3[1] ^ 0x6a6a6a6a;
+  w3[2] = w3[2] ^ 0x6a6a6a6a;
+  w3[3] = w3[3] ^ 0x6a6a6a6a;
+
+  opad[0] = SHA1M_A;
+  opad[1] = SHA1M_B;
+  opad[2] = SHA1M_C;
+  opad[3] = SHA1M_D;
+  opad[4] = SHA1M_E;
+
+  sha1_transform_vector (w0, w1, w2, w3, opad);
+}
+
+DECLSPEC void hmac_sha1_run (u32x *w0, u32x *w1, u32x *w2, u32x *w3, u32x *ipad, u32x *opad, u32x *digest)
+{
+  digest[0] = ipad[0];
+  digest[1] = ipad[1];
+  digest[2] = ipad[2];
+  digest[3] = ipad[3];
+  digest[4] = ipad[4];
+
+  sha1_transform_vector (w0, w1, w2, w3, digest);
+
+  w0[0] = digest[0];
+  w0[1] = digest[1];
+  w0[2] = digest[2];
+  w0[3] = digest[3];
+  w1[0] = digest[4];
+  w1[1] = 0x80000000;
+  w1[2] = 0;
+  w1[3] = 0;
+  w2[0] = 0;
+  w2[1] = 0;
+  w2[2] = 0;
+  w2[3] = 0;
+  w3[0] = 0;
+  w3[1] = 0;
+  w3[2] = 0;
+  w3[3] = (64 + 20) * 8;
+
+  digest[0] = opad[0];
+  digest[1] = opad[1];
+  digest[2] = opad[2];
+  digest[3] = opad[3];
+  digest[4] = opad[4];
+
+  sha1_transform_vector (w0, w1, w2, w3, digest);
+}
+
+KERNEL_FQ void m24800_m04 (KERN_ATTR_BASIC ())
+{
+  /**
+   * modifier
+   */
+
+  const u64 lid = get_local_id (0);
+
+  /**
+   * base
+   */
+
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  u32 pw_buf0[4];
+  u32 pw_buf1[4];
+
+  pw_buf0[0] = pws[gid].i[0];
+  pw_buf0[1] = pws[gid].i[1];
+  pw_buf0[2] = pws[gid].i[2];
+  pw_buf0[3] = pws[gid].i[3];
+  pw_buf1[0] = pws[gid].i[4];
+  pw_buf1[1] = pws[gid].i[5];
+  pw_buf1[2] = pws[gid].i[6];
+  pw_buf1[3] = pws[gid].i[7];
+
+  const u32 pw_l_len = pws[gid].pw_len & 63;
+
+  /**
+   * loop
+   */
+
+  for (u32 il_pos = 0; il_pos < il_cnt; il_pos += VECT_SIZE)
+  {
+    const u32x pw_r_len = pwlenx_create_combt (combs_buf, il_pos) & 63;
+
+    const u32x pw_len = (pw_l_len + pw_r_len) & 63;
+
+    const u32x pw_len2 = pw_len * 2;
+
+    /**
+     * concat password candidate
+     */
+
+    u32x wordl0[4] = { 0 };
+    u32x wordl1[4] = { 0 };
+    u32x wordl2[4] = { 0 };
+    u32x wordl3[4] = { 0 };
+
+    wordl0[0] = pw_buf0[0];
+    wordl0[1] = pw_buf0[1];
+    wordl0[2] = pw_buf0[2];
+    wordl0[3] = pw_buf0[3];
+    wordl1[0] = pw_buf1[0];
+    wordl1[1] = pw_buf1[1];
+    wordl1[2] = pw_buf1[2];
+    wordl1[3] = pw_buf1[3];
+
+    u32x wordr0[4] = { 0 };
+    u32x wordr1[4] = { 0 };
+    u32x wordr2[4] = { 0 };
+    u32x wordr3[4] = { 0 };
+
+    wordr0[0] = ix_create_combt (combs_buf, il_pos, 0);
+    wordr0[1] = ix_create_combt (combs_buf, il_pos, 1);
+    wordr0[2] = ix_create_combt (combs_buf, il_pos, 2);
+    wordr0[3] = ix_create_combt (combs_buf, il_pos, 3);
+    wordr1[0] = ix_create_combt (combs_buf, il_pos, 4);
+    wordr1[1] = ix_create_combt (combs_buf, il_pos, 5);
+    wordr1[2] = ix_create_combt (combs_buf, il_pos, 6);
+    wordr1[3] = ix_create_combt (combs_buf, il_pos, 7);
+
+    if (combs_mode == COMBINATOR_MODE_BASE_LEFT)
+    {
+      switch_buffer_by_offset_le_VV (wordr0, wordr1, wordr2, wordr3, pw_l_len);
+    }
+    else
+    {
+      switch_buffer_by_offset_le_VV (wordl0, wordl1, wordl2, wordl3, pw_r_len);
+    }
+
+    u32x w0[4];
+    u32x w1[4];
+    u32x w2[4];
+    u32x w3[4];
+
+    w0[0] = wordl0[0] | wordr0[0];
+    w0[1] = wordl0[1] | wordr0[1];
+    w0[2] = wordl0[2] | wordr0[2];
+    w0[3] = wordl0[3] | wordr0[3];
+    w1[0] = wordl1[0] | wordr1[0];
+    w1[1] = wordl1[1] | wordr1[1];
+    w1[2] = wordl1[2] | wordr1[2];
+    w1[3] = wordl1[3] | wordr1[3];
+
+    w0[0] = hc_swap32 (w0[0]);
+    w0[1] = hc_swap32 (w0[1]);
+    w0[2] = hc_swap32 (w0[2]);
+    w0[3] = hc_swap32 (w0[3]);
+    w1[0] = hc_swap32 (w1[0]);
+    w1[1] = hc_swap32 (w1[1]);
+    w1[2] = hc_swap32 (w1[2]);
+    w1[3] = hc_swap32 (w1[3]);
+
+    make_utf16beN (w1, w2, w3);
+    make_utf16beN (w0, w0, w1);
+
+    u32x x0_t[4];
+    u32x x1_t[4];
+    u32x x2_t[4];
+    u32x x3_t[4];
+
+    x0_t[0] = w0[0];
+    x0_t[1] = w0[1];
+    x0_t[2] = w0[2];
+    x0_t[3] = w0[3];
+    x1_t[0] = w1[0];
+    x1_t[1] = w1[1];
+    x1_t[2] = w1[2];
+    x1_t[3] = w1[3];
+    x2_t[0] = w2[0];
+    x2_t[1] = w2[1];
+    x2_t[2] = w2[2];
+    x2_t[3] = w2[3];
+    x3_t[0] = w3[0];
+    x3_t[1] = w3[1];
+    x3_t[2] = w3[2];
+    x3_t[3] = w3[3];
+
+    u32x ipad[5];
+    u32x opad[5];
+
+    hmac_sha1_pad (x0_t, x1_t, x2_t, x3_t, ipad, opad);
+
+    x0_t[0] = w0[0];
+    x0_t[1] = w0[1];
+    x0_t[2] = w0[2];
+    x0_t[3] = w0[3];
+    x1_t[0] = w1[0];
+    x1_t[1] = w1[1];
+    x1_t[2] = w1[2];
+    x1_t[3] = w1[3];
+    x2_t[0] = w2[0];
+    x2_t[1] = w2[1];
+    x2_t[2] = w2[2];
+    x2_t[3] = w2[3];
+    x3_t[0] = w3[0];
+    x3_t[1] = w3[1];
+    x3_t[2] = w3[2];
+    x3_t[3] = w3[3];
+
+    append_0x80_4x4_VV (x0_t, x1_t, x2_t, x3_t, pw_len2 ^ 3);
+
+    x3_t[2] = 0;
+    x3_t[3] = (64 + pw_len2) * 8;
+
+    u32x digest[5];
+
+    hmac_sha1_run (x0_t, x1_t, x2_t, x3_t, ipad, opad, digest);
+
+    COMPARE_M_SIMD (digest[3], digest[4], digest[2], digest[1]);
+  }
+}
+
+KERNEL_FQ void m24800_m08 (KERN_ATTR_BASIC ())
+{
+}
+
+KERNEL_FQ void m24800_m16 (KERN_ATTR_BASIC ())
+{
+}
+
+KERNEL_FQ void m24800_s04 (KERN_ATTR_BASIC ())
+{
+  /**
+   * modifier
+   */
+
+  const u64 lid = get_local_id (0);
+
+  /**
+   * base
+   */
+
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  u32 pw_buf0[4];
+  u32 pw_buf1[4];
+
+  pw_buf0[0] = pws[gid].i[0];
+  pw_buf0[1] = pws[gid].i[1];
+  pw_buf0[2] = pws[gid].i[2];
+  pw_buf0[3] = pws[gid].i[3];
+  pw_buf1[0] = pws[gid].i[4];
+  pw_buf1[1] = pws[gid].i[5];
+  pw_buf1[2] = pws[gid].i[6];
+  pw_buf1[3] = pws[gid].i[7];
+
+  const u32 pw_l_len = pws[gid].pw_len & 63;
+
+  /**
+   * digest
+   */
+
+  const u32 search[4] =
+  {
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R0],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R1],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R2],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R3]
+  };
+
+  /**
+   * loop
+   */
+
+  for (u32 il_pos = 0; il_pos < il_cnt; il_pos += VECT_SIZE)
+  {
+    const u32x pw_r_len = pwlenx_create_combt (combs_buf, il_pos) & 63;
+
+    const u32x pw_len = (pw_l_len + pw_r_len) & 63;
+
+    const u32x pw_len2 = pw_len * 2;
+
+    /**
+     * concat password candidate
+     */
+
+    u32x wordl0[4] = { 0 };
+    u32x wordl1[4] = { 0 };
+    u32x wordl2[4] = { 0 };
+    u32x wordl3[4] = { 0 };
+
+    wordl0[0] = pw_buf0[0];
+    wordl0[1] = pw_buf0[1];
+    wordl0[2] = pw_buf0[2];
+    wordl0[3] = pw_buf0[3];
+    wordl1[0] = pw_buf1[0];
+    wordl1[1] = pw_buf1[1];
+    wordl1[2] = pw_buf1[2];
+    wordl1[3] = pw_buf1[3];
+
+    u32x wordr0[4] = { 0 };
+    u32x wordr1[4] = { 0 };
+    u32x wordr2[4] = { 0 };
+    u32x wordr3[4] = { 0 };
+
+    wordr0[0] = ix_create_combt (combs_buf, il_pos, 0);
+    wordr0[1] = ix_create_combt (combs_buf, il_pos, 1);
+    wordr0[2] = ix_create_combt (combs_buf, il_pos, 2);
+    wordr0[3] = ix_create_combt (combs_buf, il_pos, 3);
+    wordr1[0] = ix_create_combt (combs_buf, il_pos, 4);
+    wordr1[1] = ix_create_combt (combs_buf, il_pos, 5);
+    wordr1[2] = ix_create_combt (combs_buf, il_pos, 6);
+    wordr1[3] = ix_create_combt (combs_buf, il_pos, 7);
+
+    if (combs_mode == COMBINATOR_MODE_BASE_LEFT)
+    {
+      switch_buffer_by_offset_le_VV (wordr0, wordr1, wordr2, wordr3, pw_l_len);
+    }
+    else
+    {
+      switch_buffer_by_offset_le_VV (wordl0, wordl1, wordl2, wordl3, pw_r_len);
+    }
+
+    u32x w0[4];
+    u32x w1[4];
+    u32x w2[4];
+    u32x w3[4];
+
+    w0[0] = wordl0[0] | wordr0[0];
+    w0[1] = wordl0[1] | wordr0[1];
+    w0[2] = wordl0[2] | wordr0[2];
+    w0[3] = wordl0[3] | wordr0[3];
+    w1[0] = wordl1[0] | wordr1[0];
+    w1[1] = wordl1[1] | wordr1[1];
+    w1[2] = wordl1[2] | wordr1[2];
+    w1[3] = wordl1[3] | wordr1[3];
+
+    w0[0] = hc_swap32 (w0[0]);
+    w0[1] = hc_swap32 (w0[1]);
+    w0[2] = hc_swap32 (w0[2]);
+    w0[3] = hc_swap32 (w0[3]);
+    w1[0] = hc_swap32 (w1[0]);
+    w1[1] = hc_swap32 (w1[1]);
+    w1[2] = hc_swap32 (w1[2]);
+    w1[3] = hc_swap32 (w1[3]);
+
+    make_utf16beN (w1, w2, w3);
+    make_utf16beN (w0, w0, w1);
+
+    u32x x0_t[4];
+    u32x x1_t[4];
+    u32x x2_t[4];
+    u32x x3_t[4];
+
+    x0_t[0] = w0[0];
+    x0_t[1] = w0[1];
+    x0_t[2] = w0[2];
+    x0_t[3] = w0[3];
+    x1_t[0] = w1[0];
+    x1_t[1] = w1[1];
+    x1_t[2] = w1[2];
+    x1_t[3] = w1[3];
+    x2_t[0] = w2[0];
+    x2_t[1] = w2[1];
+    x2_t[2] = w2[2];
+    x2_t[3] = w2[3];
+    x3_t[0] = w3[0];
+    x3_t[1] = w3[1];
+    x3_t[2] = w3[2];
+    x3_t[3] = w3[3];
+
+    u32x ipad[5];
+    u32x opad[5];
+
+    hmac_sha1_pad (x0_t, x1_t, x2_t, x3_t, ipad, opad);
+
+    x0_t[0] = w0[0];
+    x0_t[1] = w0[1];
+    x0_t[2] = w0[2];
+    x0_t[3] = w0[3];
+    x1_t[0] = w1[0];
+    x1_t[1] = w1[1];
+    x1_t[2] = w1[2];
+    x1_t[3] = w1[3];
+    x2_t[0] = w2[0];
+    x2_t[1] = w2[1];
+    x2_t[2] = w2[2];
+    x2_t[3] = w2[3];
+    x3_t[0] = w3[0];
+    x3_t[1] = w3[1];
+    x3_t[2] = w3[2];
+    x3_t[3] = w3[3];
+
+    append_0x80_4x4_VV (x0_t, x1_t, x2_t, x3_t, pw_len2 ^ 3);
+
+    x3_t[2] = 0;
+    x3_t[3] = (64 + pw_len2) * 8;
+
+    u32x digest[5];
+
+    hmac_sha1_run (x0_t, x1_t, x2_t, x3_t, ipad, opad, digest);
+
+    COMPARE_S_SIMD (digest[3], digest[4], digest[2], digest[1]);
+  }
+}
+
+KERNEL_FQ void m24800_s08 (KERN_ATTR_BASIC ())
+{
+}
+
+KERNEL_FQ void m24800_s16 (KERN_ATTR_BASIC ())
+{
+}
diff --git a/OpenCL/m24800_a1-pure.cl b/OpenCL/m24800_a1-pure.cl
new file mode 100644
index 000000000..df4733feb
--- /dev/null
+++ b/OpenCL/m24800_a1-pure.cl
@@ -0,0 +1,181 @@
+/**
+ * Author......: See docs/credits.txt
+ * License.....: MIT
+ */
+
+//#define NEW_SIMD_CODE
+
+#ifdef KERNEL_STATIC
+#include "inc_vendor.h"
+#include "inc_types.h"
+#include "inc_platform.cl"
+#include "inc_common.cl"
+#include "inc_scalar.cl"
+#include "inc_hash_sha1.cl"
+#endif
+
+KERNEL_FQ void m24800_mxx (KERN_ATTR_BASIC ())
+{
+  /**
+   * modifier
+   */
+
+  const u64 lid = get_local_id (0);
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  /**
+   * base
+   */
+
+  const u32 pw_len = pws[gid].pw_len;
+
+  u32 w[64] = { 0 };
+
+  for (u32 i = 0, idx = 0; i < pw_len; i += 4, idx += 1)
+  {
+    w[idx] = hc_swap32_S (pws[gid].i[idx]);
+  }
+
+  /**
+   * loop
+   */
+
+  for (u32 il_pos = 0; il_pos < il_cnt; il_pos++)
+  {
+    const u32 comb_len = combs_buf[il_pos].pw_len;
+
+    u32 c[64];
+
+    #ifdef _unroll
+    #pragma unroll
+    #endif
+    for (int idx = 0; idx < 64; idx++)
+    {
+      c[idx] = hc_swap32_S (combs_buf[il_pos].i[idx]);
+    }
+
+    switch_buffer_by_offset_1x64_be_S (c, pw_len);
+
+    #ifdef _unroll
+    #pragma unroll
+    #endif
+    for (int i = 0; i < 64; i++)
+    {
+      c[i] |= w[i];
+    }
+
+    u32 t[128] = { 0 };
+
+    // make it unicode.
+    for (u32 i = 0, idx = 0; idx < pw_len + comb_len; i += 2, idx += 1)
+    {
+        make_utf16beN (&c[idx], &t[i], &t[i+1]);
+    }
+
+    sha1_hmac_ctx_t ctx;
+
+    sha1_hmac_init (&ctx, t, (pw_len + comb_len) * 2);
+
+    sha1_hmac_update (&ctx, t, (pw_len + comb_len) * 2);
+
+    sha1_hmac_final (&ctx);
+
+    const u32 r0 = ctx.opad.h[DGST_R0];
+    const u32 r1 = ctx.opad.h[DGST_R1];
+    const u32 r2 = ctx.opad.h[DGST_R2];
+    const u32 r3 = ctx.opad.h[DGST_R3];
+
+    COMPARE_M_SCALAR (r0, r1, r2, r3);
+  }
+}
+
+KERNEL_FQ void m24800_sxx (KERN_ATTR_BASIC ())
+{
+  /**
+   * modifier
+   */
+
+  const u64 lid = get_local_id (0);
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  /**
+   * digest
+   */
+
+  const u32 search[4] =
+  {
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R0],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R1],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R2],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R3]
+  };
+
+  /**
+   * base
+   */
+
+  const u32 pw_len = pws[gid].pw_len;
+
+  u32 w[64] = { 0 };
+
+  for (u32 i = 0, idx = 0; i < pw_len; i += 4, idx += 1)
+  {
+    w[idx] = hc_swap32_S (pws[gid].i[idx]);
+  }
+
+  /**
+   * loop
+   */
+
+  for (u32 il_pos = 0; il_pos < il_cnt; il_pos++)
+  {
+    const u32 comb_len = combs_buf[il_pos].pw_len;
+
+    u32 c[64];
+
+    #ifdef _unroll
+    #pragma unroll
+    #endif
+    for (int idx = 0; idx < 64; idx++)
+    {
+      c[idx] = hc_swap32_S (combs_buf[il_pos].i[idx]);
+    }
+
+    switch_buffer_by_offset_1x64_be_S (c, pw_len);
+
+    #ifdef _unroll
+    #pragma unroll
+    #endif
+    for (int i = 0; i < 64; i++)
+    {
+      c[i] |= w[i];
+    }
+
+    u32 t[128] = { 0 };
+
+    // make it unicode.
+    for (u32 i = 0, idx = 0; idx < pw_len + comb_len; i += 2, idx += 1)
+    {
+        make_utf16beN (&c[idx], &t[i], &t[i+1]);
+    }
+
+    sha1_hmac_ctx_t ctx;
+
+    sha1_hmac_init (&ctx, t, (pw_len + comb_len) * 2);
+
+    sha1_hmac_update (&ctx, t, (pw_len + comb_len) * 2);
+
+    sha1_hmac_final (&ctx);
+
+    const u32 r0 = ctx.opad.h[DGST_R0];
+    const u32 r1 = ctx.opad.h[DGST_R1];
+    const u32 r2 = ctx.opad.h[DGST_R2];
+    const u32 r3 = ctx.opad.h[DGST_R3];
+
+    COMPARE_S_SCALAR (r0, r1, r2, r3);
+  }
+}
diff --git a/OpenCL/m24800_a3-optimized.cl b/OpenCL/m24800_a3-optimized.cl
new file mode 100644
index 000000000..f64f8af3c
--- /dev/null
+++ b/OpenCL/m24800_a3-optimized.cl
@@ -0,0 +1,612 @@
+/**
+ * Author......: See docs/credits.txt
+ * License.....: MIT
+ */
+
+#define NEW_SIMD_CODE
+
+#ifdef KERNEL_STATIC
+#include "inc_vendor.h"
+#include "inc_types.h"
+#include "inc_platform.cl"
+#include "inc_common.cl"
+#include "inc_simd.cl"
+#include "inc_hash_sha1.cl"
+#endif
+
+DECLSPEC void hmac_sha1_pad (u32x *w0, u32x *w1, u32x *w2, u32x *w3, u32x *ipad, u32x *opad)
+{
+  w0[0] = w0[0] ^ 0x36363636;
+  w0[1] = w0[1] ^ 0x36363636;
+  w0[2] = w0[2] ^ 0x36363636;
+  w0[3] = w0[3] ^ 0x36363636;
+  w1[0] = w1[0] ^ 0x36363636;
+  w1[1] = w1[1] ^ 0x36363636;
+  w1[2] = w1[2] ^ 0x36363636;
+  w1[3] = w1[3] ^ 0x36363636;
+  w2[0] = w2[0] ^ 0x36363636;
+  w2[1] = w2[1] ^ 0x36363636;
+  w2[2] = w2[2] ^ 0x36363636;
+  w2[3] = w2[3] ^ 0x36363636;
+  w3[0] = w3[0] ^ 0x36363636;
+  w3[1] = w3[1] ^ 0x36363636;
+  w3[2] = w3[2] ^ 0x36363636;
+  w3[3] = w3[3] ^ 0x36363636;
+
+  ipad[0] = SHA1M_A;
+  ipad[1] = SHA1M_B;
+  ipad[2] = SHA1M_C;
+  ipad[3] = SHA1M_D;
+  ipad[4] = SHA1M_E;
+
+  sha1_transform_vector (w0, w1, w2, w3, ipad);
+
+  w0[0] = w0[0] ^ 0x6a6a6a6a;
+  w0[1] = w0[1] ^ 0x6a6a6a6a;
+  w0[2] = w0[2] ^ 0x6a6a6a6a;
+  w0[3] = w0[3] ^ 0x6a6a6a6a;
+  w1[0] = w1[0] ^ 0x6a6a6a6a;
+  w1[1] = w1[1] ^ 0x6a6a6a6a;
+  w1[2] = w1[2] ^ 0x6a6a6a6a;
+  w1[3] = w1[3] ^ 0x6a6a6a6a;
+  w2[0] = w2[0] ^ 0x6a6a6a6a;
+  w2[1] = w2[1] ^ 0x6a6a6a6a;
+  w2[2] = w2[2] ^ 0x6a6a6a6a;
+  w2[3] = w2[3] ^ 0x6a6a6a6a;
+  w3[0] = w3[0] ^ 0x6a6a6a6a;
+  w3[1] = w3[1] ^ 0x6a6a6a6a;
+  w3[2] = w3[2] ^ 0x6a6a6a6a;
+  w3[3] = w3[3] ^ 0x6a6a6a6a;
+
+  opad[0] = SHA1M_A;
+  opad[1] = SHA1M_B;
+  opad[2] = SHA1M_C;
+  opad[3] = SHA1M_D;
+  opad[4] = SHA1M_E;
+
+  sha1_transform_vector (w0, w1, w2, w3, opad);
+}
+
+DECLSPEC void hmac_sha1_run (u32x *w0, u32x *w1, u32x *w2, u32x *w3, u32x *ipad, u32x *opad, u32x *digest)
+{
+  digest[0] = ipad[0];
+  digest[1] = ipad[1];
+  digest[2] = ipad[2];
+  digest[3] = ipad[3];
+  digest[4] = ipad[4];
+
+  sha1_transform_vector (w0, w1, w2, w3, digest);
+
+  w0[0] = digest[0];
+  w0[1] = digest[1];
+  w0[2] = digest[2];
+  w0[3] = digest[3];
+  w1[0] = digest[4];
+  w1[1] = 0x80000000;
+  w1[2] = 0;
+  w1[3] = 0;
+  w2[0] = 0;
+  w2[1] = 0;
+  w2[2] = 0;
+  w2[3] = 0;
+  w3[0] = 0;
+  w3[1] = 0;
+  w3[2] = 0;
+  w3[3] = (64 + 20) * 8;
+
+  digest[0] = opad[0];
+  digest[1] = opad[1];
+  digest[2] = opad[2];
+  digest[3] = opad[3];
+  digest[4] = opad[4];
+
+  sha1_transform_vector (w0, w1, w2, w3, digest);
+}
+
+DECLSPEC void m24800m (u32 *w0, u32 *w1, u32 *w2, u32 *w3, const u32 pw_len, KERN_ATTR_BASIC ())
+{
+  /**
+   * modifier
+   */
+
+  const u64 gid = get_global_id (0);
+  const u64 lid = get_local_id (0);
+
+  /**
+   * loop
+   */
+
+  u32 w0l = w0[0];
+
+  for (u32 il_pos = 0; il_pos < il_cnt; il_pos += VECT_SIZE)
+  {
+    const u32x w0r = ix_create_bft (bfs_buf, il_pos);
+
+    const u32x w0lr = w0l | w0r;
+
+    /**
+     * pads
+     */
+
+    u32x w0_t[4];
+    u32x w1_t[4];
+    u32x w2_t[4];
+    u32x w3_t[4];
+
+    w0_t[0] = w0lr;
+    w0_t[1] = w0[1];
+    w0_t[2] = w0[2];
+    w0_t[3] = w0[3];
+    w1_t[0] = w1[0];
+    w1_t[1] = w1[1];
+    w1_t[2] = w1[2];
+    w1_t[3] = w1[3];
+    w2_t[0] = w2[0];
+    w2_t[1] = w2[1];
+    w2_t[2] = w2[2];
+    w2_t[3] = w2[3];
+    w3_t[0] = w3[0];
+    w3_t[1] = w3[1];
+    w3_t[2] = w3[2];
+    w3_t[3] = w3[3];
+
+    //make_utf16beN (w1_t, w2_t, w3_t);
+    //make_utf16beN (w0_t, w0_t, w1_t);
+
+    u32x x0_t[4];
+    u32x x1_t[4];
+    u32x x2_t[4];
+    u32x x3_t[4];
+
+    x0_t[0] = w0_t[0];
+    x0_t[1] = w0_t[1];
+    x0_t[2] = w0_t[2];
+    x0_t[3] = w0_t[3];
+    x1_t[0] = w1_t[0];
+    x1_t[1] = w1_t[1];
+    x1_t[2] = w1_t[2];
+    x1_t[3] = w1_t[3];
+    x2_t[0] = w2_t[0];
+    x2_t[1] = w2_t[1];
+    x2_t[2] = w2_t[2];
+    x2_t[3] = w2_t[3];
+    x3_t[0] = w3_t[0];
+    x3_t[1] = w3_t[1];
+    x3_t[2] = w3_t[2];
+    x3_t[3] = w3_t[3];
+
+    u32x ipad[5];
+    u32x opad[5];
+
+    hmac_sha1_pad (x0_t, x1_t, x2_t, x3_t, ipad, opad);
+
+    x0_t[0] = w0_t[0];
+    x0_t[1] = w0_t[1];
+    x0_t[2] = w0_t[2];
+    x0_t[3] = w0_t[3];
+    x1_t[0] = w1_t[0];
+    x1_t[1] = w1_t[1];
+    x1_t[2] = w1_t[2];
+    x1_t[3] = w1_t[3];
+    x2_t[0] = w2_t[0];
+    x2_t[1] = w2_t[1];
+    x2_t[2] = w2_t[2];
+    x2_t[3] = w2_t[3];
+    x3_t[0] = w3_t[0];
+    x3_t[1] = w3_t[1];
+    x3_t[2] = w3_t[2];
+    x3_t[3] = w3_t[3];
+
+    append_0x80_4x4 (x0_t, x1_t, x2_t, x3_t, pw_len ^ 3);
+
+    x3_t[2] = 0;
+    x3_t[3] = (64 + pw_len) * 8;
+
+    u32x digest[5];
+
+    hmac_sha1_run (x0_t, x1_t, x2_t, x3_t, ipad, opad, digest);
+
+    COMPARE_M_SIMD (digest[3], digest[4], digest[2], digest[1]);
+  }
+}
+
+DECLSPEC void m24800s (u32 *w0, u32 *w1, u32 *w2, u32 *w3, const u32 pw_len, KERN_ATTR_BASIC ())
+{
+  /**
+   * modifier
+   */
+
+  const u64 gid = get_global_id (0);
+  const u64 lid = get_local_id (0);
+
+  /**
+   * digest
+   */
+
+  const u32 search[4] =
+  {
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R0],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R1],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R2],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R3]
+  };
+
+  /**
+   * loop
+   */
+
+  u32 w0l = w0[0];
+
+  for (u32 il_pos = 0; il_pos < il_cnt; il_pos += VECT_SIZE)
+  {
+    const u32x w0r = ix_create_bft (bfs_buf, il_pos);
+
+    const u32x w0lr = w0l | w0r;
+
+    /**
+     * pads
+     */
+
+    u32x w0_t[4];
+    u32x w1_t[4];
+    u32x w2_t[4];
+    u32x w3_t[4];
+
+    w0_t[0] = w0lr;
+    w0_t[1] = w0[1];
+    w0_t[2] = w0[2];
+    w0_t[3] = w0[3];
+    w1_t[0] = w1[0];
+    w1_t[1] = w1[1];
+    w1_t[2] = w1[2];
+    w1_t[3] = w1[3];
+    w2_t[0] = w2[0];
+    w2_t[1] = w2[1];
+    w2_t[2] = w2[2];
+    w2_t[3] = w2[3];
+    w3_t[0] = w3[0];
+    w3_t[1] = w3[1];
+    w3_t[2] = w3[2];
+    w3_t[3] = w3[3];
+
+    //make_utf16beN (w1_t, w2_t, w3_t);
+    //make_utf16beN (w0_t, w0_t, w1_t);
+
+    u32x x0_t[4];
+    u32x x1_t[4];
+    u32x x2_t[4];
+    u32x x3_t[4];
+
+    x0_t[0] = w0_t[0];
+    x0_t[1] = w0_t[1];
+    x0_t[2] = w0_t[2];
+    x0_t[3] = w0_t[3];
+    x1_t[0] = w1_t[0];
+    x1_t[1] = w1_t[1];
+    x1_t[2] = w1_t[2];
+    x1_t[3] = w1_t[3];
+    x2_t[0] = w2_t[0];
+    x2_t[1] = w2_t[1];
+    x2_t[2] = w2_t[2];
+    x2_t[3] = w2_t[3];
+    x3_t[0] = w3_t[0];
+    x3_t[1] = w3_t[1];
+    x3_t[2] = w3_t[2];
+    x3_t[3] = w3_t[3];
+
+    u32x ipad[5];
+    u32x opad[5];
+
+    hmac_sha1_pad (x0_t, x1_t, x2_t, x3_t, ipad, opad);
+
+    x0_t[0] = w0_t[0];
+    x0_t[1] = w0_t[1];
+    x0_t[2] = w0_t[2];
+    x0_t[3] = w0_t[3];
+    x1_t[0] = w1_t[0];
+    x1_t[1] = w1_t[1];
+    x1_t[2] = w1_t[2];
+    x1_t[3] = w1_t[3];
+    x2_t[0] = w2_t[0];
+    x2_t[1] = w2_t[1];
+    x2_t[2] = w2_t[2];
+    x2_t[3] = w2_t[3];
+    x3_t[0] = w3_t[0];
+    x3_t[1] = w3_t[1];
+    x3_t[2] = w3_t[2];
+    x3_t[3] = w3_t[3];
+
+    append_0x80_4x4 (x0_t, x1_t, x2_t, x3_t, pw_len ^ 3);
+
+    x3_t[2] = 0;
+    x3_t[3] = (64 + pw_len) * 8;
+
+    u32x digest[5];
+
+    hmac_sha1_run (x0_t, x1_t, x2_t, x3_t, ipad, opad, digest);
+
+    COMPARE_S_SIMD (digest[3], digest[4], digest[2], digest[1]);
+  }
+}
+
+KERNEL_FQ void m24800_m04 (KERN_ATTR_BASIC ())
+{
+  /**
+   * base
+   */
+
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  u32 w0[4];
+
+  w0[0] = pws[gid].i[ 0];
+  w0[1] = pws[gid].i[ 1];
+  w0[2] = pws[gid].i[ 2];
+  w0[3] = pws[gid].i[ 3];
+
+  u32 w1[4];
+
+  w1[0] = 0;
+  w1[1] = 0;
+  w1[2] = 0;
+  w1[3] = 0;
+
+  u32 w2[4];
+
+  w2[0] = 0;
+  w2[1] = 0;
+  w2[2] = 0;
+  w2[3] = 0;
+
+  u32 w3[4];
+
+  w3[0] = 0;
+  w3[1] = 0;
+  w3[2] = 0;
+  w3[3] = 0;
+
+  const u32 pw_len = pws[gid].pw_len & 63;
+
+  /**
+   * main
+   */
+
+  m24800m (w0, w1, w2, w3, pw_len, pws, rules_buf, combs_buf, bfs_buf, tmps, hooks, bitmaps_buf_s1_a, bitmaps_buf_s1_b, bitmaps_buf_s1_c, bitmaps_buf_s1_d, bitmaps_buf_s2_a, bitmaps_buf_s2_b, bitmaps_buf_s2_c, bitmaps_buf_s2_d, plains_buf, digests_buf, hashes_shown, salt_bufs, esalt_bufs, d_return_buf, d_extra0_buf, d_extra1_buf, d_extra2_buf, d_extra3_buf, bitmap_mask, bitmap_shift1, bitmap_shift2, SALT_POS, loop_pos, loop_cnt, il_cnt, digests_cnt, DIGESTS_OFFSET, combs_mode, pws_pos, gid_max);
+}
+
+KERNEL_FQ void m24800_m08 (KERN_ATTR_BASIC ())
+{
+  /**
+   * base
+   */
+
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  u32 w0[4];
+
+  w0[0] = pws[gid].i[ 0];
+  w0[1] = pws[gid].i[ 1];
+  w0[2] = pws[gid].i[ 2];
+  w0[3] = pws[gid].i[ 3];
+
+  u32 w1[4];
+
+  w1[0] = pws[gid].i[ 4];
+  w1[1] = pws[gid].i[ 5];
+  w1[2] = pws[gid].i[ 6];
+  w1[3] = pws[gid].i[ 7];
+
+  u32 w2[4];
+
+  w2[0] = 0;
+  w2[1] = 0;
+  w2[2] = 0;
+  w2[3] = 0;
+
+  u32 w3[4];
+
+  w3[0] = 0;
+  w3[1] = 0;
+  w3[2] = 0;
+  w3[3] = 0;
+
+  const u32 pw_len = pws[gid].pw_len & 63;
+
+  /**
+   * main
+   */
+
+  m24800m (w0, w1, w2, w3, pw_len, pws, rules_buf, combs_buf, bfs_buf, tmps, hooks, bitmaps_buf_s1_a, bitmaps_buf_s1_b, bitmaps_buf_s1_c, bitmaps_buf_s1_d, bitmaps_buf_s2_a, bitmaps_buf_s2_b, bitmaps_buf_s2_c, bitmaps_buf_s2_d, plains_buf, digests_buf, hashes_shown, salt_bufs, esalt_bufs, d_return_buf, d_extra0_buf, d_extra1_buf, d_extra2_buf, d_extra3_buf, bitmap_mask, bitmap_shift1, bitmap_shift2, SALT_POS, loop_pos, loop_cnt, il_cnt, digests_cnt, DIGESTS_OFFSET, combs_mode, pws_pos, gid_max);
+}
+
+KERNEL_FQ void m24800_m16 (KERN_ATTR_BASIC ())
+{
+  /**
+   * base
+   */
+
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  u32 w0[4];
+
+  w0[0] = pws[gid].i[ 0];
+  w0[1] = pws[gid].i[ 1];
+  w0[2] = pws[gid].i[ 2];
+  w0[3] = pws[gid].i[ 3];
+
+  u32 w1[4];
+
+  w1[0] = pws[gid].i[ 4];
+  w1[1] = pws[gid].i[ 5];
+  w1[2] = pws[gid].i[ 6];
+  w1[3] = pws[gid].i[ 7];
+
+  u32 w2[4];
+
+  w2[0] = pws[gid].i[ 8];
+  w2[1] = pws[gid].i[ 9];
+  w2[2] = pws[gid].i[10];
+  w2[3] = pws[gid].i[11];
+
+  u32 w3[4];
+
+  w3[0] = pws[gid].i[12];
+  w3[1] = pws[gid].i[13];
+  w3[2] = 0;
+  w3[3] = 0;
+
+  const u32 pw_len = pws[gid].pw_len & 63;
+
+  /**
+   * main
+   */
+
+  m24800m (w0, w1, w2, w3, pw_len, pws, rules_buf, combs_buf, bfs_buf, tmps, hooks, bitmaps_buf_s1_a, bitmaps_buf_s1_b, bitmaps_buf_s1_c, bitmaps_buf_s1_d, bitmaps_buf_s2_a, bitmaps_buf_s2_b, bitmaps_buf_s2_c, bitmaps_buf_s2_d, plains_buf, digests_buf, hashes_shown, salt_bufs, esalt_bufs, d_return_buf, d_extra0_buf, d_extra1_buf, d_extra2_buf, d_extra3_buf, bitmap_mask, bitmap_shift1, bitmap_shift2, SALT_POS, loop_pos, loop_cnt, il_cnt, digests_cnt, DIGESTS_OFFSET, combs_mode, pws_pos, gid_max);
+}
+
+KERNEL_FQ void m24800_s04 (KERN_ATTR_BASIC ())
+{
+  /**
+   * base
+   */
+
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  u32 w0[4];
+
+  w0[0] = pws[gid].i[ 0];
+  w0[1] = pws[gid].i[ 1];
+  w0[2] = pws[gid].i[ 2];
+  w0[3] = pws[gid].i[ 3];
+
+  u32 w1[4];
+
+  w1[0] = 0;
+  w1[1] = 0;
+  w1[2] = 0;
+  w1[3] = 0;
+
+  u32 w2[4];
+
+  w2[0] = 0;
+  w2[1] = 0;
+  w2[2] = 0;
+  w2[3] = 0;
+
+  u32 w3[4];
+
+  w3[0] = 0;
+  w3[1] = 0;
+  w3[2] = 0;
+  w3[3] = 0;
+
+  const u32 pw_len = pws[gid].pw_len & 63;
+
+  /**
+   * main
+   */
+
+  m24800s (w0, w1, w2, w3, pw_len, pws, rules_buf, combs_buf, bfs_buf, tmps, hooks, bitmaps_buf_s1_a, bitmaps_buf_s1_b, bitmaps_buf_s1_c, bitmaps_buf_s1_d, bitmaps_buf_s2_a, bitmaps_buf_s2_b, bitmaps_buf_s2_c, bitmaps_buf_s2_d, plains_buf, digests_buf, hashes_shown, salt_bufs, esalt_bufs, d_return_buf, d_extra0_buf, d_extra1_buf, d_extra2_buf, d_extra3_buf, bitmap_mask, bitmap_shift1, bitmap_shift2, SALT_POS, loop_pos, loop_cnt, il_cnt, digests_cnt, DIGESTS_OFFSET, combs_mode, pws_pos, gid_max);
+}
+
+KERNEL_FQ void m24800_s08 (KERN_ATTR_BASIC ())
+{
+  /**
+   * base
+   */
+
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  u32 w0[4];
+
+  w0[0] = pws[gid].i[ 0];
+  w0[1] = pws[gid].i[ 1];
+  w0[2] = pws[gid].i[ 2];
+  w0[3] = pws[gid].i[ 3];
+
+  u32 w1[4];
+
+  w1[0] = pws[gid].i[ 4];
+  w1[1] = pws[gid].i[ 5];
+  w1[2] = pws[gid].i[ 6];
+  w1[3] = pws[gid].i[ 7];
+
+  u32 w2[4];
+
+  w2[0] = 0;
+  w2[1] = 0;
+  w2[2] = 0;
+  w2[3] = 0;
+
+  u32 w3[4];
+
+  w3[0] = 0;
+  w3[1] = 0;
+  w3[2] = 0;
+  w3[3] = 0;
+
+  const u32 pw_len = pws[gid].pw_len & 63;
+
+  /**
+   * main
+   */
+
+  m24800s (w0, w1, w2, w3, pw_len, pws, rules_buf, combs_buf, bfs_buf, tmps, hooks, bitmaps_buf_s1_a, bitmaps_buf_s1_b, bitmaps_buf_s1_c, bitmaps_buf_s1_d, bitmaps_buf_s2_a, bitmaps_buf_s2_b, bitmaps_buf_s2_c, bitmaps_buf_s2_d, plains_buf, digests_buf, hashes_shown, salt_bufs, esalt_bufs, d_return_buf, d_extra0_buf, d_extra1_buf, d_extra2_buf, d_extra3_buf, bitmap_mask, bitmap_shift1, bitmap_shift2, SALT_POS, loop_pos, loop_cnt, il_cnt, digests_cnt, DIGESTS_OFFSET, combs_mode, pws_pos, gid_max);
+}
+
+KERNEL_FQ void m24800_s16 (KERN_ATTR_BASIC ())
+{
+  /**
+   * base
+   */
+
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  u32 w0[4];
+
+  w0[0] = pws[gid].i[ 0];
+  w0[1] = pws[gid].i[ 1];
+  w0[2] = pws[gid].i[ 2];
+  w0[3] = pws[gid].i[ 3];
+
+  u32 w1[4];
+
+  w1[0] = pws[gid].i[ 4];
+  w1[1] = pws[gid].i[ 5];
+  w1[2] = pws[gid].i[ 6];
+  w1[3] = pws[gid].i[ 7];
+
+  u32 w2[4];
+
+  w2[0] = pws[gid].i[ 8];
+  w2[1] = pws[gid].i[ 9];
+  w2[2] = pws[gid].i[10];
+  w2[3] = pws[gid].i[11];
+
+  u32 w3[4];
+
+  w3[0] = pws[gid].i[12];
+  w3[1] = pws[gid].i[13];
+  w3[2] = 0;
+  w3[3] = 0;
+
+  const u32 pw_len = pws[gid].pw_len & 63;
+
+  /**
+   * main
+   */
+
+  m24800s (w0, w1, w2, w3, pw_len, pws, rules_buf, combs_buf, bfs_buf, tmps, hooks, bitmaps_buf_s1_a, bitmaps_buf_s1_b, bitmaps_buf_s1_c, bitmaps_buf_s1_d, bitmaps_buf_s2_a, bitmaps_buf_s2_b, bitmaps_buf_s2_c, bitmaps_buf_s2_d, plains_buf, digests_buf, hashes_shown, salt_bufs, esalt_bufs, d_return_buf, d_extra0_buf, d_extra1_buf, d_extra2_buf, d_extra3_buf, bitmap_mask, bitmap_shift1, bitmap_shift2, SALT_POS, loop_pos, loop_cnt, il_cnt, digests_cnt, DIGESTS_OFFSET, combs_mode, pws_pos, gid_max);
+}
diff --git a/OpenCL/m24800_a3-pure.cl b/OpenCL/m24800_a3-pure.cl
new file mode 100644
index 000000000..825b256ca
--- /dev/null
+++ b/OpenCL/m24800_a3-pure.cl
@@ -0,0 +1,151 @@
+/**
+ * Author......: See docs/credits.txt
+ * License.....: MIT
+ */
+
+#define NEW_SIMD_CODE
+
+#ifdef KERNEL_STATIC
+#include "inc_vendor.h"
+#include "inc_types.h"
+#include "inc_platform.cl"
+#include "inc_common.cl"
+#include "inc_simd.cl"
+#include "inc_hash_sha1.cl"
+#endif
+
+KERNEL_FQ void m24800_mxx (KERN_ATTR_VECTOR ())
+{
+  /**
+   * modifier
+   */
+
+  const u64 lid = get_local_id (0);
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  /**
+   * base
+   */
+
+  const u32 pw_len = pws[gid].pw_len;
+
+  u32x w[64] = { 0 };
+
+  for (u32 i = 0, idx = 0; i < pw_len; i += 4, idx += 1)
+  {
+    w[idx] = pws[gid].i[idx];
+  }
+
+  /**
+   * loop
+   */
+
+  u32x w0l = w[0];
+
+  for (u32 il_pos = 0; il_pos < il_cnt; il_pos += VECT_SIZE)
+  {
+    const u32x w0r = words_buf_r[il_pos / VECT_SIZE];
+
+    const u32x w0 = w0l | w0r;
+
+    w[0] = w0;
+
+    u32x t[128] = { 0 };
+
+    for (u32 i = 0, idx = 0; idx < pw_len; i += 2, idx += 1)
+    {
+      make_utf16beN (&w[idx], &t[i + 0], &t[i + 1]);
+    }
+
+    sha1_hmac_ctx_vector_t ctx;
+
+    sha1_hmac_init_vector (&ctx, t, pw_len * 2);
+
+    sha1_hmac_update_vector (&ctx, t, pw_len * 2);
+
+    sha1_hmac_final_vector (&ctx);
+
+    const u32x r0 = ctx.opad.h[DGST_R0];
+    const u32x r1 = ctx.opad.h[DGST_R1];
+    const u32x r2 = ctx.opad.h[DGST_R2];
+    const u32x r3 = ctx.opad.h[DGST_R3];
+
+    COMPARE_M_SIMD (r0, r1, r2, r3);
+  }
+}
+
+KERNEL_FQ void m24800_sxx (KERN_ATTR_VECTOR ())
+{
+  /**
+   * modifier
+   */
+
+  const u64 lid = get_local_id (0);
+  const u64 gid = get_global_id (0);
+
+  if (gid >= gid_max) return;
+
+  /**
+   * digest
+   */
+
+  const u32 search[4] =
+  {
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R0],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R1],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R2],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R3]
+  };
+
+  /**
+   * base
+   */
+
+  const u32 pw_len = pws[gid].pw_len;
+
+  u32x w[64] = { 0 };
+
+  for (u32 i = 0, idx = 0; i < pw_len; i += 4, idx += 1)
+  {
+    w[idx] = pws[gid].i[idx];
+  }
+
+  /**
+   * loop
+   */
+
+  u32x w0l = w[0];
+
+  for (u32 il_pos = 0; il_pos < il_cnt; il_pos += VECT_SIZE)
+  {
+    const u32x w0r = words_buf_r[il_pos / VECT_SIZE];
+
+    const u32x w0 = w0l | w0r;
+
+    w[0] = w0;
+
+    u32x t[128] = { 0 };
+
+    for (u32 i = 0, idx = 0; idx < pw_len; i += 2, idx += 1)
+    {
+      make_utf16beN (&w[idx], &t[i + 0], &t[i + 1]);
+    }
+
+    sha1_hmac_ctx_vector_t ctx;
+
+    sha1_hmac_init_vector (&ctx, t, pw_len * 2);
+
+    sha1_hmac_update_vector (&ctx, t, pw_len * 2);
+
+    sha1_hmac_final_vector (&ctx);
+
+    const u32x r0 = ctx.opad.h[DGST_R0];
+    const u32x r1 = ctx.opad.h[DGST_R1];
+    const u32x r2 = ctx.opad.h[DGST_R2];
+    const u32x r3 = ctx.opad.h[DGST_R3];
+
+    COMPARE_S_SIMD (r0, r1, r2, r3);
+  }
+}
diff --git a/OpenCL/m24900_a0-optimized.cl b/OpenCL/m24900_a0-optimized.cl
index 033b1ee72..312691021 100644
--- a/OpenCL/m24900_a0-optimized.cl
+++ b/OpenCL/m24900_a0-optimized.cl
@@ -46,22 +46,6 @@ KERNEL_FQ void m24900_m04 (KERN_ATTR_RULES ())
 
   const u32 pw_len = pws[gid].pw_len & 63;
 
-  /**
-   * lookup table
-   */
-
-  const u8 sof_lut[64] =
-  {
-   0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
-   0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
-   0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
-   0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56,
-   0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64,
-   0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
-   0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74,
-   0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x00, 0x00
-  };
-
   /**
    * loop
    */
@@ -160,37 +144,21 @@ KERNEL_FQ void m24900_m04 (KERN_ATTR_RULES ())
     c += MD5M_C;
     d += MD5M_D;
 
-    u16 t_abcd = ((a & 0xff) + ((a >> 8) & 0xff));
-    u8 a_12 = (t_abcd % 0x3e);
+    const u32x a0 = (((a >>  0) & 0xff) + ((a >>  8) & 0xff)) % 62;
+    const u32x a1 = (((a >> 16) & 0xff) + ((a >> 24) & 0xff)) % 62;
+    const u32x b0 = (((b >>  0) & 0xff) + ((b >>  8) & 0xff)) % 62;
+    const u32x b1 = (((b >> 16) & 0xff) + ((b >> 24) & 0xff)) % 62;
+    const u32x c0 = (((c >>  0) & 0xff) + ((c >>  8) & 0xff)) % 62;
+    const u32x c1 = (((c >> 16) & 0xff) + ((c >> 24) & 0xff)) % 62;
+    const u32x d0 = (((d >>  0) & 0xff) + ((d >>  8) & 0xff)) % 62;
+    const u32x d1 = (((d >> 16) & 0xff) + ((d >> 24) & 0xff)) % 62;
 
-    t_abcd = (((a >> 16 )& 0xff) + ((a >> 24) & 0xff));
-    u8 a_34 = (t_abcd % 0x3e);
-
-    t_abcd = ((b & 0xff) + ((b >> 8) & 0xff));
-    u8 b_12 = (t_abcd % 0x3e);
-
-    t_abcd = (((b >> 16) & 0xff) + ((b >> 24) & 0xff));
-    u8 b_34 = (t_abcd % 0x3e);
-
-    t_abcd = ((c & 0xff) + ((c >> 8) & 0xff));
-    u8 c_12 = (t_abcd % 0x3e);
-
-    t_abcd = (((c >> 16 )& 0xff) + ((c >> 24) & 0xff));
-    u8 c_34 = (t_abcd % 0x3e);
-
-    t_abcd = ((d & 0xff) + ((d >> 8) & 0xff));
-    u8 d_12 = (t_abcd % 0x3e);
-
-    t_abcd = (((d >> 16) & 0xff) + ((d >> 24) & 0xff));
-    u8 d_34 = (t_abcd % 0x3e);
-
-    a = (sof_lut[a_12]) + (sof_lut[a_34] << 8) + (sof_lut[b_12] << 16) + (sof_lut[b_34] << 24);
-    b = (sof_lut[c_12]) + (sof_lut[c_34] << 8) + (sof_lut[d_12] << 16) + (sof_lut[d_34] << 24);
-
-    u32x z = 0;
-
-    COMPARE_M_SIMD (a, b, z, z);
+    const u32x ax = (a0 <<  0) | (a1 <<  8);
+    const u32x bx = (b0 <<  0) | (b1 <<  8);
+    const u32x cx = (c0 <<  0) | (c1 <<  8);
+    const u32x dx = (d0 <<  0) | (d1 <<  8);
 
+    COMPARE_M_SIMD (ax, bx, cx, dx);
   }
 }
 
@@ -240,24 +208,8 @@ KERNEL_FQ void m24900_s04 (KERN_ATTR_RULES ())
   {
     digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R0],
     digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R1],
-    0,
-    0
-  };
-
-  /**
-   * lookup table
-   */
-
-  const u8 sof_lut[64] = 
-  {
-   0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 
-   0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 
-   0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 
-   0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 
-   0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 
-   0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 
-   0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 
-   0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x00, 0x00
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R2],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R3]
   };
 
   /**
@@ -358,37 +310,21 @@ KERNEL_FQ void m24900_s04 (KERN_ATTR_RULES ())
     c += MD5M_C;
     d += MD5M_D;
 
-    u16 t_abcd = ((a & 0xff) + ((a >> 8) & 0xff));
-    u8 a_12 = (t_abcd % 0x3e);
+    const u32x a0 = (((a >>  0) & 0xff) + ((a >>  8) & 0xff)) % 62;
+    const u32x a1 = (((a >> 16) & 0xff) + ((a >> 24) & 0xff)) % 62;
+    const u32x b0 = (((b >>  0) & 0xff) + ((b >>  8) & 0xff)) % 62;
+    const u32x b1 = (((b >> 16) & 0xff) + ((b >> 24) & 0xff)) % 62;
+    const u32x c0 = (((c >>  0) & 0xff) + ((c >>  8) & 0xff)) % 62;
+    const u32x c1 = (((c >> 16) & 0xff) + ((c >> 24) & 0xff)) % 62;
+    const u32x d0 = (((d >>  0) & 0xff) + ((d >>  8) & 0xff)) % 62;
+    const u32x d1 = (((d >> 16) & 0xff) + ((d >> 24) & 0xff)) % 62;
 
-    t_abcd = (((a >> 16 )& 0xff) + ((a >> 24) & 0xff));
-    u8 a_34 = (t_abcd % 0x3e);
-
-    t_abcd = ((b & 0xff) + ((b >> 8) & 0xff));
-    u8 b_12 = (t_abcd % 0x3e);
-
-    t_abcd = (((b >> 16) & 0xff) + ((b >> 24) & 0xff));
-    u8 b_34 = (t_abcd % 0x3e);
-
-    t_abcd = ((c & 0xff) + ((c >> 8) & 0xff));
-    u8 c_12 = (t_abcd % 0x3e);
-
-    t_abcd = (((c >> 16 )& 0xff) + ((c >> 24) & 0xff));
-    u8 c_34 = (t_abcd % 0x3e);
-
-    t_abcd = ((d & 0xff) + ((d >> 8) & 0xff));
-    u8 d_12 = (t_abcd % 0x3e);
-
-    t_abcd = (((d >> 16) & 0xff) + ((d >> 24) & 0xff));
-    u8 d_34 = (t_abcd % 0x3e);
-
-    a = (sof_lut[a_12]) + (sof_lut[a_34] << 8) + (sof_lut[b_12] << 16) + (sof_lut[b_34] << 24);
-    b = (sof_lut[c_12]) + (sof_lut[c_34] << 8) + (sof_lut[d_12] << 16) + (sof_lut[d_34] << 24);
-
-    u32x z = 0;
-
-    COMPARE_S_SIMD (a, b, z, z);
+    const u32x ax = (a0 <<  0) | (a1 <<  8);
+    const u32x bx = (b0 <<  0) | (b1 <<  8);
+    const u32x cx = (c0 <<  0) | (c1 <<  8);
+    const u32x dx = (d0 <<  0) | (d1 <<  8);
 
+    COMPARE_S_SIMD (ax, bx, cx, dx);
   }
 }
 
diff --git a/OpenCL/m24900_a1-optimized.cl b/OpenCL/m24900_a1-optimized.cl
index 3a44018fc..a25797ee2 100644
--- a/OpenCL/m24900_a1-optimized.cl
+++ b/OpenCL/m24900_a1-optimized.cl
@@ -45,22 +45,6 @@ KERNEL_FQ void m24900_m04 (KERN_ATTR_BASIC ())
 
   const u32 pw_l_len = pws[gid].pw_len & 63;
 
-  /**
-   * lookup table
-   */
-
-  const u8 sof_lut[64] =
-  {
-   0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
-   0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
-   0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
-   0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56,
-   0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64,
-   0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
-   0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74,
-   0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x00, 0x00
-  };
-
   /**
    * loop
    */
@@ -218,36 +202,21 @@ KERNEL_FQ void m24900_m04 (KERN_ATTR_BASIC ())
     c += MD5M_C;
     d += MD5M_D;
 
-    u16 t_abcd = ((a & 0xff) + ((a >> 8) & 0xff));
-    u8 a_12 = (t_abcd % 0x3e);
+    const u32x a0 = (((a >>  0) & 0xff) + ((a >>  8) & 0xff)) % 62;
+    const u32x a1 = (((a >> 16) & 0xff) + ((a >> 24) & 0xff)) % 62;
+    const u32x b0 = (((b >>  0) & 0xff) + ((b >>  8) & 0xff)) % 62;
+    const u32x b1 = (((b >> 16) & 0xff) + ((b >> 24) & 0xff)) % 62;
+    const u32x c0 = (((c >>  0) & 0xff) + ((c >>  8) & 0xff)) % 62;
+    const u32x c1 = (((c >> 16) & 0xff) + ((c >> 24) & 0xff)) % 62;
+    const u32x d0 = (((d >>  0) & 0xff) + ((d >>  8) & 0xff)) % 62;
+    const u32x d1 = (((d >> 16) & 0xff) + ((d >> 24) & 0xff)) % 62;
 
-    t_abcd = (((a >> 16 )& 0xff) + ((a >> 24) & 0xff));
-    u8 a_34 = (t_abcd % 0x3e);
+    const u32x ax = (a0 <<  0) | (a1 <<  8);
+    const u32x bx = (b0 <<  0) | (b1 <<  8);
+    const u32x cx = (c0 <<  0) | (c1 <<  8);
+    const u32x dx = (d0 <<  0) | (d1 <<  8);
 
-    t_abcd = ((b & 0xff) + ((b >> 8) & 0xff));
-    u8 b_12 = (t_abcd % 0x3e);
-
-    t_abcd = (((b >> 16) & 0xff) + ((b >> 24) & 0xff));
-    u8 b_34 = (t_abcd % 0x3e);
-
-    t_abcd = ((c & 0xff) + ((c >> 8) & 0xff));
-    u8 c_12 = (t_abcd % 0x3e);
-
-    t_abcd = (((c >> 16 )& 0xff) + ((c >> 24) & 0xff));
-    u8 c_34 = (t_abcd % 0x3e);
-
-    t_abcd = ((d & 0xff) + ((d >> 8) & 0xff));
-    u8 d_12 = (t_abcd % 0x3e);
-
-    t_abcd = (((d >> 16) & 0xff) + ((d >> 24) & 0xff));
-    u8 d_34 = (t_abcd % 0x3e);
-
-    a = (sof_lut[a_12]) + (sof_lut[a_34] << 8) + (sof_lut[b_12] << 16) + (sof_lut[b_34] << 24);
-    b = (sof_lut[c_12]) + (sof_lut[c_34] << 8) + (sof_lut[d_12] << 16) + (sof_lut[d_34] << 24);
-
-    u32x z = 0;
-
-    COMPARE_M_SIMD (a, b, z, z);
+    COMPARE_M_SIMD (ax, bx, cx, dx);
   }
 }
 
@@ -289,22 +258,6 @@ KERNEL_FQ void m24900_s04 (KERN_ATTR_BASIC ())
 
   const u32 pw_l_len = pws[gid].pw_len & 63;
 
-  /**
-   * lookup table
-   */
-
-  const u8 sof_lut[64] =
-  {
-   0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
-   0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
-   0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
-   0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56,
-   0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64,
-   0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
-   0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74,
-   0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x00, 0x00
-  };
-
   /**
    * digest
    */
@@ -313,8 +266,8 @@ KERNEL_FQ void m24900_s04 (KERN_ATTR_BASIC ())
   {
     digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R0],
     digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R1],
-    0,
-    0
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R2],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R3]
   };
 
   /**
@@ -474,36 +427,21 @@ KERNEL_FQ void m24900_s04 (KERN_ATTR_BASIC ())
     c += MD5M_C;
     d += MD5M_D;
 
-    u16 t_abcd = ((a & 0xff) + ((a >> 8) & 0xff));
-    u8 a_12 = (t_abcd % 0x3e);
+    const u32x a0 = (((a >>  0) & 0xff) + ((a >>  8) & 0xff)) % 62;
+    const u32x a1 = (((a >> 16) & 0xff) + ((a >> 24) & 0xff)) % 62;
+    const u32x b0 = (((b >>  0) & 0xff) + ((b >>  8) & 0xff)) % 62;
+    const u32x b1 = (((b >> 16) & 0xff) + ((b >> 24) & 0xff)) % 62;
+    const u32x c0 = (((c >>  0) & 0xff) + ((c >>  8) & 0xff)) % 62;
+    const u32x c1 = (((c >> 16) & 0xff) + ((c >> 24) & 0xff)) % 62;
+    const u32x d0 = (((d >>  0) & 0xff) + ((d >>  8) & 0xff)) % 62;
+    const u32x d1 = (((d >> 16) & 0xff) + ((d >> 24) & 0xff)) % 62;
 
-    t_abcd = (((a >> 16 )& 0xff) + ((a >> 24) & 0xff));
-    u8 a_34 = (t_abcd % 0x3e);
+    const u32x ax = (a0 <<  0) | (a1 <<  8);
+    const u32x bx = (b0 <<  0) | (b1 <<  8);
+    const u32x cx = (c0 <<  0) | (c1 <<  8);
+    const u32x dx = (d0 <<  0) | (d1 <<  8);
 
-    t_abcd = ((b & 0xff) + ((b >> 8) & 0xff));
-    u8 b_12 = (t_abcd % 0x3e);
-
-    t_abcd = (((b >> 16) & 0xff) + ((b >> 24) & 0xff));
-    u8 b_34 = (t_abcd % 0x3e);
-
-    t_abcd = ((c & 0xff) + ((c >> 8) & 0xff));
-    u8 c_12 = (t_abcd % 0x3e);
-
-    t_abcd = (((c >> 16 )& 0xff) + ((c >> 24) & 0xff));
-    u8 c_34 = (t_abcd % 0x3e);
-
-    t_abcd = ((d & 0xff) + ((d >> 8) & 0xff));
-    u8 d_12 = (t_abcd % 0x3e);
-
-    t_abcd = (((d >> 16) & 0xff) + ((d >> 24) & 0xff));
-    u8 d_34 = (t_abcd % 0x3e);
-
-    a = (sof_lut[a_12]) + (sof_lut[a_34] << 8) + (sof_lut[b_12] << 16) + (sof_lut[b_34] << 24);
-    b = (sof_lut[c_12]) + (sof_lut[c_34] << 8) + (sof_lut[d_12] << 16) + (sof_lut[d_34] << 24);
-
-    u32x z = 0;
-
-    COMPARE_S_SIMD (a, b, z, z);
+    COMPARE_S_SIMD (ax, bx, cx, dx);
   }
 }
 
diff --git a/OpenCL/m24900_a3-optimized.cl b/OpenCL/m24900_a3-optimized.cl
index 71a5c01d8..42b8bbbfa 100644
--- a/OpenCL/m24900_a3-optimized.cl
+++ b/OpenCL/m24900_a3-optimized.cl
@@ -23,22 +23,6 @@ DECLSPEC void m24900m (u32 *w0, u32 *w1, u32 *w2, u32 *w3, const u32 pw_len, KER
   const u64 gid = get_global_id (0);
   const u64 lid = get_local_id (0);
 
-  /**
-   * lookup table
-   */
-
-  const u8 sof_lut[64] =
-  {
-   0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
-   0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
-   0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
-   0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56,
-   0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64,
-   0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
-   0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74,
-   0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x00, 0x00
-  };
-
   /**
    * loop
    */
@@ -157,36 +141,21 @@ DECLSPEC void m24900m (u32 *w0, u32 *w1, u32 *w2, u32 *w3, const u32 pw_len, KER
     c += MD5M_C;
     d += MD5M_D;
 
-    u16 t_abcd = ((a & 0xff) + ((a >> 8) & 0xff));
-    u8 a_12 = (t_abcd % 0x3e);
+    const u32x a0 = (((a >>  0) & 0xff) + ((a >>  8) & 0xff)) % 62;
+    const u32x a1 = (((a >> 16) & 0xff) + ((a >> 24) & 0xff)) % 62;
+    const u32x b0 = (((b >>  0) & 0xff) + ((b >>  8) & 0xff)) % 62;
+    const u32x b1 = (((b >> 16) & 0xff) + ((b >> 24) & 0xff)) % 62;
+    const u32x c0 = (((c >>  0) & 0xff) + ((c >>  8) & 0xff)) % 62;
+    const u32x c1 = (((c >> 16) & 0xff) + ((c >> 24) & 0xff)) % 62;
+    const u32x d0 = (((d >>  0) & 0xff) + ((d >>  8) & 0xff)) % 62;
+    const u32x d1 = (((d >> 16) & 0xff) + ((d >> 24) & 0xff)) % 62;
 
-    t_abcd = (((a >> 16 )& 0xff) + ((a >> 24) & 0xff));
-    u8 a_34 = (t_abcd % 0x3e);
+    const u32x ax = (a0 <<  0) | (a1 <<  8);
+    const u32x bx = (b0 <<  0) | (b1 <<  8);
+    const u32x cx = (c0 <<  0) | (c1 <<  8);
+    const u32x dx = (d0 <<  0) | (d1 <<  8);
 
-    t_abcd = ((b & 0xff) + ((b >> 8) & 0xff));
-    u8 b_12 = (t_abcd % 0x3e);
-
-    t_abcd = (((b >> 16) & 0xff) + ((b >> 24) & 0xff));
-    u8 b_34 = (t_abcd % 0x3e);
-
-    t_abcd = ((c & 0xff) + ((c >> 8) & 0xff));
-    u8 c_12 = (t_abcd % 0x3e);
-
-    t_abcd = (((c >> 16 )& 0xff) + ((c >> 24) & 0xff));
-    u8 c_34 = (t_abcd % 0x3e);
-
-    t_abcd = ((d & 0xff) + ((d >> 8) & 0xff));
-    u8 d_12 = (t_abcd % 0x3e);
-
-    t_abcd = (((d >> 16) & 0xff) + ((d >> 24) & 0xff));
-    u8 d_34 = (t_abcd % 0x3e);
-
-    a = (sof_lut[a_12]) + (sof_lut[a_34] << 8) + (sof_lut[b_12] << 16) + (sof_lut[b_34] << 24);
-    b = (sof_lut[c_12]) + (sof_lut[c_34] << 8) + (sof_lut[d_12] << 16) + (sof_lut[d_34] << 24);
-
-    u32x z = 0;
-
-    COMPARE_M_SIMD (a, b, z, z);
+    COMPARE_M_SIMD (ax, bx, cx, dx);
   }
 }
 
@@ -207,24 +176,8 @@ DECLSPEC void m24900s (u32 *w0, u32 *w1, u32 *w2, u32 *w3, const u32 pw_len, KER
   {
     digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R0],
     digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R1],
-    0,
-    0
-  };
-
-  /**
-   * lookup table
-   */
-
-  const u8 sof_lut[64] =
-  {
-   0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
-   0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
-   0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
-   0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56,
-   0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64,
-   0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
-   0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74,
-   0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x00, 0x00
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R2],
+    digests_buf[DIGESTS_OFFSET].digest_buf[DGST_R3],
   };
 
   /**
@@ -345,36 +298,21 @@ DECLSPEC void m24900s (u32 *w0, u32 *w1, u32 *w2, u32 *w3, const u32 pw_len, KER
     c += MD5M_C;
     d += MD5M_D;
 
-    u16 t_abcd = ((a & 0xff) + ((a >> 8) & 0xff));
-    u8 a_12 = (t_abcd % 0x3e);
+    const u32x a0 = (((a >>  0) & 0xff) + ((a >>  8) & 0xff)) % 62;
+    const u32x a1 = (((a >> 16) & 0xff) + ((a >> 24) & 0xff)) % 62;
+    const u32x b0 = (((b >>  0) & 0xff) + ((b >>  8) & 0xff)) % 62;
+    const u32x b1 = (((b >> 16) & 0xff) + ((b >> 24) & 0xff)) % 62;
+    const u32x c0 = (((c >>  0) & 0xff) + ((c >>  8) & 0xff)) % 62;
+    const u32x c1 = (((c >> 16) & 0xff) + ((c >> 24) & 0xff)) % 62;
+    const u32x d0 = (((d >>  0) & 0xff) + ((d >>  8) & 0xff)) % 62;
+    const u32x d1 = (((d >> 16) & 0xff) + ((d >> 24) & 0xff)) % 62;
 
-    t_abcd = (((a >> 16 )& 0xff) + ((a >> 24) & 0xff));
-    u8 a_34 = (t_abcd % 0x3e);
+    const u32x ax = (a0 <<  0) | (a1 <<  8);
+    const u32x bx = (b0 <<  0) | (b1 <<  8);
+    const u32x cx = (c0 <<  0) | (c1 <<  8);
+    const u32x dx = (d0 <<  0) | (d1 <<  8);
 
-    t_abcd = ((b & 0xff) + ((b >> 8) & 0xff));
-    u8 b_12 = (t_abcd % 0x3e);
-
-    t_abcd = (((b >> 16) & 0xff) + ((b >> 24) & 0xff));
-    u8 b_34 = (t_abcd % 0x3e);
-
-    t_abcd = ((c & 0xff) + ((c >> 8) & 0xff));
-    u8 c_12 = (t_abcd % 0x3e);
-
-    t_abcd = (((c >> 16 )& 0xff) + ((c >> 24) & 0xff));
-    u8 c_34 = (t_abcd % 0x3e);
-
-    t_abcd = ((d & 0xff) + ((d >> 8) & 0xff));
-    u8 d_12 = (t_abcd % 0x3e);
-
-    t_abcd = (((d >> 16) & 0xff) + ((d >> 24) & 0xff));
-    u8 d_34 = (t_abcd % 0x3e);
-
-    a = (sof_lut[a_12]) + (sof_lut[a_34] << 8) + (sof_lut[b_12] << 16) + (sof_lut[b_34] << 24);
-    b = (sof_lut[c_12]) + (sof_lut[c_34] << 8) + (sof_lut[d_12] << 16) + (sof_lut[d_34] << 24);
-
-    u32x z = 0;
-
-    COMPARE_S_SIMD (a, b, z, z);
+    COMPARE_S_SIMD (ax, bx, cx, dx);
   }
 }
 
diff --git a/docs/changes.txt b/docs/changes.txt
index cc63abd57..9acbd3def 100644
--- a/docs/changes.txt
+++ b/docs/changes.txt
@@ -4,17 +4,20 @@
 ## Algorithms
 ##
 
-- Added hash-mode: Bitwarden
-- Added hash-mode: BestCrypt v3 Volume Encryption
 - Added hash-mode: Apple iWork
 - Added hash-mode: AxCrypt 2 AES-128
 - Added hash-mode: AxCrypt 2 AES-256
+- Added hash-mode: BestCrypt v3 Volume Encryption
+- Added hash-mode: Bitwarden
+- Added hash-mode: Dahua Authentication MD5
 - Added hash-mode: PKCS#8 Private Keys
 - Added hash-mode: RAR3-p (Compressed)
 - Added hash-mode: RAR3-p (Uncompressed)
 - Added hash-mode: RSA/DSA/EC/OPENSSH Private Keys
+- Added hash-mode: SQLCipher
+- Added hash-mode: Stuffit5
+- Added hash-mode: Umbraco HMAC-SHA1
 - Added hash-mode: sha1(sha1($pass).$salt)
-- Added hash-mode: Dahua Authentication MD5
 
 ##
 ## Bugs
diff --git a/docs/readme.txt b/docs/readme.txt
index 38b7fe300..232bde33b 100644
--- a/docs/readme.txt
+++ b/docs/readme.txt
@@ -216,6 +216,7 @@ NVIDIA GPUs require "NVIDIA Driver" (440.64 or later) and "CUDA Toolkit" (9.0 or
 - MySQL4.1/MySQL5
 - MySQL $A$ (sha256crypt)
 - Sybase ASE
+- SQLCipher
 - hMailServer
 - DNSSEC (NSEC3)
 - CRAM-MD5 Dovecot
@@ -313,6 +314,7 @@ NVIDIA GPUs require "NVIDIA Driver" (440.64 or later) and "CUDA Toolkit" (9.0 or
 - iTunes backup >= 10.0
 - WinZip
 - Android Backup
+- Stuffit5
 - AxCrypt 1
 - AxCrypt 1 in-memory SHA1
 - AxCrypt 2 AES-128
@@ -324,6 +326,7 @@ NVIDIA GPUs require "NVIDIA Driver" (440.64 or later) and "CUDA Toolkit" (9.0 or
 - SMF (Simple Machines Forum) > v1.1
 - MediaWiki B type
 - Redmine
+- Umbraco HMAC-SHA1
 - Joomla < 2.5.18
 - OpenCart
 - PrestaShop
diff --git a/src/modules/module_24600.c b/src/modules/module_24600.c
new file mode 100644
index 000000000..7a2ef5dc6
--- /dev/null
+++ b/src/modules/module_24600.c
@@ -0,0 +1,355 @@
+/**
+ * Author......: See docs/credits.txt
+ * License.....: MIT
+ */
+
+#include "common.h"
+#include "types.h"
+#include "modules.h"
+#include "bitops.h"
+#include "convert.h"
+#include "shared.h"
+
+static const u32   ATTACK_EXEC    = ATTACK_EXEC_OUTSIDE_KERNEL;
+static const u32   DGST_POS0      = 0;
+static const u32   DGST_POS1      = 1;
+static const u32   DGST_POS2      = 2;
+static const u32   DGST_POS3      = 3;
+static const u32   DGST_SIZE      = DGST_SIZE_4_4;
+static const u32   HASH_CATEGORY  = HASH_CATEGORY_DATABASE_SERVER;
+static const char *HASH_NAME      = "SQLCipher";
+static const u64   KERN_TYPE      = 24610;
+static const u32   OPTI_TYPE      = OPTI_TYPE_ZERO_BYTE
+                                  | OPTI_TYPE_USES_BITS_64
+                                  | OPTI_TYPE_SLOW_HASH_SIMD_LOOP;
+static const u64   OPTS_TYPE      = OPTS_TYPE_PT_GENERATE_LE
+                                  | OPTS_TYPE_SELF_TEST_DISABLE;
+static const u32   SALT_TYPE      = SALT_TYPE_EMBEDDED;
+static const char *ST_PASS        = "hashcat";
+static const char *ST_HASH        = "SQLCIPHER*1*64000*25548249195677404156261816261456*85b5e156e1cf1e0be5e9f4217186817b*33435c230bbc7989bbd027630e3f47cd";
+
+u32         module_attack_exec    (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return ATTACK_EXEC;     }
+u32         module_dgst_pos0      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return DGST_POS0;       }
+u32         module_dgst_pos1      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return DGST_POS1;       }
+u32         module_dgst_pos2      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return DGST_POS2;       }
+u32         module_dgst_pos3      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return DGST_POS3;       }
+u32         module_dgst_size      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return DGST_SIZE;       }
+u32         module_hash_category  (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return HASH_CATEGORY;   }
+const char *module_hash_name      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return HASH_NAME;       }
+u64         module_kern_type      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return KERN_TYPE;       }
+u32         module_opti_type      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return OPTI_TYPE;       }
+u64         module_opts_type      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return OPTS_TYPE;       }
+u32         module_salt_type      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return SALT_TYPE;       }
+const char *module_st_hash        (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return ST_HASH;         }
+const char *module_st_pass        (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return ST_PASS;         }
+
+typedef struct sqlcipher_sha1_tmp
+{
+  u32  ipad[5];
+  u32  opad[5];
+
+  u32  dgst[10];
+  u32  out[10];
+
+} sqlcipher_sha1_tmp_t;
+
+typedef struct sqlcipher_sha256_tmp
+{
+  u32  ipad[8];
+  u32  opad[8];
+
+  u32  dgst[8];
+  u32  out[8];
+
+} sqlcipher_sha256_tmp_t;
+
+typedef struct sqlcipher_sha512_tmp
+{
+  u64  ipad[8];
+  u64  opad[8];
+
+  u64  dgst[8];
+  u64  out[8];
+
+} sqlcipher_sha512_tmp_t;
+
+typedef struct sqlcipher
+{
+  u32 iv_buf[4];
+  u32 data_buf[4];
+
+  u32 type;
+
+} sqlcipher_t;
+
+typedef enum kern_type_sqlcipher
+{
+  KERN_TYPE_SQLCIPHER_SHA1   = 24610,
+  KERN_TYPE_SQLCIPHER_SHA256 = 24620,
+  KERN_TYPE_SQLCIPHER_SHA512 = 24630,
+
+} kern_type_sqlcipher_t;
+
+static const char *SIGNATURE_SQLCIPHER = "SQLCIPHER";
+
+u64 module_esalt_size (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra)
+{
+  const u64 esalt_size = (const u64) sizeof (sqlcipher_t);
+
+  return esalt_size;
+}
+
+u64 module_tmp_size (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra)
+{
+  const u64 tmp_size = (const u64) sizeof (sqlcipher_sha512_tmp_t); // we just select the largest
+
+  return tmp_size;
+}
+
+u32 module_pw_max (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra)
+{
+  // this overrides the reductions of PW_MAX in case optimized kernel is selected
+  // IOW, even in optimized kernel mode it support length 256
+
+  const u32 pw_max = PW_MAX;
+
+  return pw_max;
+}
+
+u64 module_kern_type_dynamic (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const void *digest_buf, MAYBE_UNUSED const salt_t *salt, MAYBE_UNUSED const void *esalt_buf, MAYBE_UNUSED const void *hook_salt_buf, MAYBE_UNUSED const hashinfo_t *hash_info)
+{
+  const sqlcipher_t *sqlcipher = (const sqlcipher_t *) esalt_buf;
+
+  u64 kern_type = -1;
+
+  if (sqlcipher->type == 1)
+  {
+    kern_type = KERN_TYPE_SQLCIPHER_SHA1;
+  }
+  else if (sqlcipher->type == 2)
+  {
+    kern_type = KERN_TYPE_SQLCIPHER_SHA256;
+  }
+  else if (sqlcipher->type == 3)
+  {
+    kern_type = KERN_TYPE_SQLCIPHER_SHA512;
+  }
+  else
+  {
+    return (PARSER_HASH_LENGTH);
+  }
+
+  return kern_type;
+}
+
+int module_hash_decode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED void *digest_buf, MAYBE_UNUSED salt_t *salt, MAYBE_UNUSED void *esalt_buf, MAYBE_UNUSED void *hook_salt_buf, MAYBE_UNUSED hashinfo_t *hash_info, const char *line_buf, MAYBE_UNUSED const int line_len)
+{
+  u32 *digest = (u32 *) digest_buf;
+
+  sqlcipher_t *sqlcipher = (sqlcipher_t *) esalt_buf;
+
+  token_t token;
+
+  token.token_cnt  = 6;
+
+  token.signatures_cnt    = 1;
+  token.signatures_buf[0] = SIGNATURE_SQLCIPHER;
+
+  token.sep[0]     = '*';
+  token.len_min[0] = 9;
+  token.len_max[0] = 9;
+  token.attr[0]    = TOKEN_ATTR_VERIFY_LENGTH
+                   | TOKEN_ATTR_VERIFY_SIGNATURE;
+
+  token.sep[1]     = '*';
+  token.len_min[1] = 1;
+  token.len_max[1] = 1;
+  token.attr[1]    = TOKEN_ATTR_VERIFY_LENGTH
+                   | TOKEN_ATTR_VERIFY_DIGIT;
+
+  token.sep[2]     = '*';
+  token.len_min[2] = 1;
+  token.len_max[2] = 6;
+  token.attr[2]    = TOKEN_ATTR_VERIFY_LENGTH
+                   | TOKEN_ATTR_VERIFY_DIGIT;
+
+  token.sep[3]     = '*';
+  token.len_min[3] = 32;
+  token.len_max[3] = 32;
+  token.attr[3]    = TOKEN_ATTR_VERIFY_LENGTH
+                   | TOKEN_ATTR_VERIFY_HEX;
+
+  token.sep[4]     = '*';
+  token.len_min[4] = 32;
+  token.len_max[4] = 32;
+  token.attr[4]    = TOKEN_ATTR_VERIFY_LENGTH
+                   | TOKEN_ATTR_VERIFY_HEX;
+
+  token.sep[5]     = '*';
+  token.len_min[5] = 32;
+  token.len_max[5] = 32;
+  token.attr[5]    = TOKEN_ATTR_VERIFY_LENGTH
+                   | TOKEN_ATTR_VERIFY_HEX;
+
+  const int rc_tokenizer = input_tokenizer ((const u8 *) line_buf, line_len, &token);
+
+  if (rc_tokenizer != PARSER_OK) return (rc_tokenizer);
+
+  // type
+
+  const u8 *type_pos = token.buf[1];
+
+  const int type = hc_strtoul ((const char *) type_pos, NULL, 10);
+
+  if ((type != 1) && (type != 2) && (type != 3)) return (PARSER_SIGNATURE_UNMATCHED);
+
+  sqlcipher->type = type;
+
+  // cipher
+
+  const u8 *iter_pos = token.buf[2];
+
+  int iter = hc_strtoul ((const char *) iter_pos, NULL, 10);
+
+  salt->salt_iter = iter - 1;
+
+  // salt buffer
+
+  const u8 *salt_pos = token.buf[3];
+
+  salt->salt_buf[0] = hex_to_u32 (salt_pos +  0);
+  salt->salt_buf[1] = hex_to_u32 (salt_pos +  8);
+  salt->salt_buf[2] = hex_to_u32 (salt_pos + 16);
+  salt->salt_buf[3] = hex_to_u32 (salt_pos + 24);
+
+  salt->salt_len = 16;
+
+  // IV buffer
+
+  const u8 *iv_pos = token.buf[4];
+
+  sqlcipher->iv_buf[0] = hex_to_u32 (iv_pos +  0);
+  sqlcipher->iv_buf[1] = hex_to_u32 (iv_pos +  8);
+  sqlcipher->iv_buf[2] = hex_to_u32 (iv_pos + 16);
+  sqlcipher->iv_buf[3] = hex_to_u32 (iv_pos + 24);
+
+  // data buffer
+
+  const u8 *data_pos = token.buf[5];
+
+  sqlcipher->data_buf[0] = hex_to_u32 (data_pos +  0);
+  sqlcipher->data_buf[1] = hex_to_u32 (data_pos +  8);
+  sqlcipher->data_buf[2] = hex_to_u32 (data_pos + 16);
+  sqlcipher->data_buf[3] = hex_to_u32 (data_pos + 24);
+
+  // hash
+
+  digest[0] = sqlcipher->data_buf[0];
+  digest[1] = sqlcipher->data_buf[1];
+  digest[2] = sqlcipher->data_buf[2];
+  digest[3] = sqlcipher->data_buf[3];
+
+  return (PARSER_OK);
+}
+
+int module_hash_encode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const void *digest_buf, MAYBE_UNUSED const salt_t *salt, MAYBE_UNUSED const void *esalt_buf, MAYBE_UNUSED const void *hook_salt_buf, MAYBE_UNUSED const hashinfo_t *hash_info, char *line_buf, MAYBE_UNUSED const int line_size)
+{
+  sqlcipher_t *sqlcipher = (sqlcipher_t *) esalt_buf;
+
+  u8 *out_buf = (u8 *) line_buf;
+
+  const int out_len = snprintf ((char *) out_buf, line_size, "%s*%d*%d*%08x%08x%08x%08x*%08x%08x%08x%08x*%08x%08x%08x%08x",
+    SIGNATURE_SQLCIPHER,
+    sqlcipher->type,
+    salt->salt_iter + 1,
+    byte_swap_32 (salt->salt_buf[0]),
+    byte_swap_32 (salt->salt_buf[1]),
+    byte_swap_32 (salt->salt_buf[2]),
+    byte_swap_32 (salt->salt_buf[3]),
+    byte_swap_32 (sqlcipher->iv_buf[0]),
+    byte_swap_32 (sqlcipher->iv_buf[1]),
+    byte_swap_32 (sqlcipher->iv_buf[2]),
+    byte_swap_32 (sqlcipher->iv_buf[3]),
+    byte_swap_32 (sqlcipher->data_buf[0]),
+    byte_swap_32 (sqlcipher->data_buf[1]),
+    byte_swap_32 (sqlcipher->data_buf[2]),
+    byte_swap_32 (sqlcipher->data_buf[3]));
+
+  return out_len;
+}
+
+void module_init (module_ctx_t *module_ctx)
+{
+  module_ctx->module_context_size             = MODULE_CONTEXT_SIZE_CURRENT;
+  module_ctx->module_interface_version        = MODULE_INTERFACE_VERSION_CURRENT;
+
+  module_ctx->module_attack_exec              = module_attack_exec;
+  module_ctx->module_benchmark_esalt          = MODULE_DEFAULT;
+  module_ctx->module_benchmark_hook_salt      = MODULE_DEFAULT;
+  module_ctx->module_benchmark_mask           = MODULE_DEFAULT;
+  module_ctx->module_benchmark_salt           = MODULE_DEFAULT;
+  module_ctx->module_build_plain_postprocess  = MODULE_DEFAULT;
+  module_ctx->module_deep_comp_kernel         = MODULE_DEFAULT;
+  module_ctx->module_dgst_pos0                = module_dgst_pos0;
+  module_ctx->module_dgst_pos1                = module_dgst_pos1;
+  module_ctx->module_dgst_pos2                = module_dgst_pos2;
+  module_ctx->module_dgst_pos3                = module_dgst_pos3;
+  module_ctx->module_dgst_size                = module_dgst_size;
+  module_ctx->module_dictstat_disable         = MODULE_DEFAULT;
+  module_ctx->module_esalt_size               = module_esalt_size;
+  module_ctx->module_extra_buffer_size        = MODULE_DEFAULT;
+  module_ctx->module_extra_tmp_size           = MODULE_DEFAULT;
+  module_ctx->module_forced_outfile_format    = MODULE_DEFAULT;
+  module_ctx->module_hash_binary_count        = MODULE_DEFAULT;
+  module_ctx->module_hash_binary_parse        = MODULE_DEFAULT;
+  module_ctx->module_hash_binary_save         = MODULE_DEFAULT;
+  module_ctx->module_hash_decode_potfile      = MODULE_DEFAULT;
+  module_ctx->module_hash_decode_zero_hash    = MODULE_DEFAULT;
+  module_ctx->module_hash_decode              = module_hash_decode;
+  module_ctx->module_hash_encode_status       = MODULE_DEFAULT;
+  module_ctx->module_hash_encode_potfile      = MODULE_DEFAULT;
+  module_ctx->module_hash_encode              = module_hash_encode;
+  module_ctx->module_hash_init_selftest       = MODULE_DEFAULT;
+  module_ctx->module_hash_mode                = MODULE_DEFAULT;
+  module_ctx->module_hash_category            = module_hash_category;
+  module_ctx->module_hash_name                = module_hash_name;
+  module_ctx->module_hashes_count_min         = MODULE_DEFAULT;
+  module_ctx->module_hashes_count_max         = MODULE_DEFAULT;
+  module_ctx->module_hlfmt_disable            = MODULE_DEFAULT;
+  module_ctx->module_hook_extra_param_size    = MODULE_DEFAULT;
+  module_ctx->module_hook_extra_param_init    = MODULE_DEFAULT;
+  module_ctx->module_hook_extra_param_term    = MODULE_DEFAULT;
+  module_ctx->module_hook12                   = MODULE_DEFAULT;
+  module_ctx->module_hook23                   = MODULE_DEFAULT;
+  module_ctx->module_hook_salt_size           = MODULE_DEFAULT;
+  module_ctx->module_hook_size                = MODULE_DEFAULT;
+  module_ctx->module_jit_build_options        = MODULE_DEFAULT;
+  module_ctx->module_jit_cache_disable        = MODULE_DEFAULT;
+  module_ctx->module_kernel_accel_max         = MODULE_DEFAULT;
+  module_ctx->module_kernel_accel_min         = MODULE_DEFAULT;
+  module_ctx->module_kernel_loops_max         = MODULE_DEFAULT;
+  module_ctx->module_kernel_loops_min         = MODULE_DEFAULT;
+  module_ctx->module_kernel_threads_max       = MODULE_DEFAULT;
+  module_ctx->module_kernel_threads_min       = MODULE_DEFAULT;
+  module_ctx->module_kern_type                = module_kern_type;
+  module_ctx->module_kern_type_dynamic        = module_kern_type_dynamic;
+  module_ctx->module_opti_type                = module_opti_type;
+  module_ctx->module_opts_type                = module_opts_type;
+  module_ctx->module_outfile_check_disable    = MODULE_DEFAULT;
+  module_ctx->module_outfile_check_nocomp     = MODULE_DEFAULT;
+  module_ctx->module_potfile_custom_check     = MODULE_DEFAULT;
+  module_ctx->module_potfile_disable          = MODULE_DEFAULT;
+  module_ctx->module_potfile_keep_all_hashes  = MODULE_DEFAULT;
+  module_ctx->module_pwdump_column            = MODULE_DEFAULT;
+  module_ctx->module_pw_max                   = module_pw_max;
+  module_ctx->module_pw_min                   = MODULE_DEFAULT;
+  module_ctx->module_salt_max                 = MODULE_DEFAULT;
+  module_ctx->module_salt_min                 = MODULE_DEFAULT;
+  module_ctx->module_salt_type                = module_salt_type;
+  module_ctx->module_separator                = MODULE_DEFAULT;
+  module_ctx->module_st_hash                  = module_st_hash;
+  module_ctx->module_st_pass                  = module_st_pass;
+  module_ctx->module_tmp_size                 = module_tmp_size;
+  module_ctx->module_unstable_warning         = MODULE_DEFAULT;
+  module_ctx->module_warmup_disable           = MODULE_DEFAULT;
+}
diff --git a/src/modules/module_24700.c b/src/modules/module_24700.c
new file mode 100644
index 000000000..04163dc37
--- /dev/null
+++ b/src/modules/module_24700.c
@@ -0,0 +1,182 @@
+/**
+ * Author......: See docs/credits.txt
+ * License.....: MIT
+ */
+
+#include "common.h"
+#include "types.h"
+#include "modules.h"
+#include "bitops.h"
+#include "convert.h"
+#include "shared.h"
+
+static const u32   ATTACK_EXEC    = ATTACK_EXEC_INSIDE_KERNEL;
+static const u32   DGST_POS0      = 0;
+static const u32   DGST_POS1      = 1;
+static const u32   DGST_POS2      = 2;
+static const u32   DGST_POS3      = 3;
+static const u32   DGST_SIZE      = DGST_SIZE_4_4;
+static const u32   HASH_CATEGORY  = HASH_CATEGORY_ARCHIVE;
+static const char *HASH_NAME      = "Stuffit5";
+static const u64   KERN_TYPE      = 24700;
+static const u32   OPTI_TYPE      = OPTI_TYPE_ZERO_BYTE
+                                  | OPTI_TYPE_PRECOMPUTE_INIT
+                                  | OPTI_TYPE_EARLY_SKIP;
+static const u64   OPTS_TYPE      = OPTS_TYPE_PT_GENERATE_LE
+                                  | OPTS_TYPE_PT_ADD80
+                                  | OPTS_TYPE_PT_ADDBITS14;
+static const u32   SALT_TYPE      = SALT_TYPE_NONE;
+static const char *ST_PASS        = "hashcat";
+static const char *ST_HASH        = "66a75cb059";
+
+u32         module_attack_exec    (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return ATTACK_EXEC;     }
+u32         module_dgst_pos0      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return DGST_POS0;       }
+u32         module_dgst_pos1      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return DGST_POS1;       }
+u32         module_dgst_pos2      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return DGST_POS2;       }
+u32         module_dgst_pos3      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return DGST_POS3;       }
+u32         module_dgst_size      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return DGST_SIZE;       }
+u32         module_hash_category  (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return HASH_CATEGORY;   }
+const char *module_hash_name      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return HASH_NAME;       }
+u64         module_kern_type      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return KERN_TYPE;       }
+u32         module_opti_type      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return OPTI_TYPE;       }
+u64         module_opts_type      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return OPTS_TYPE;       }
+u32         module_salt_type      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return SALT_TYPE;       }
+const char *module_st_hash        (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return ST_HASH;         }
+const char *module_st_pass        (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return ST_PASS;         }
+
+int module_hash_decode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED void *digest_buf, MAYBE_UNUSED salt_t *salt, MAYBE_UNUSED void *esalt_buf, MAYBE_UNUSED void *hook_salt_buf, MAYBE_UNUSED hashinfo_t *hash_info, const char *line_buf, MAYBE_UNUSED const int line_len)
+{
+  u32 *digest = (u32 *) digest_buf;
+
+  token_t token;
+
+  token.token_cnt  = 1;
+
+  token.len_min[0] = 10;
+  token.len_max[0] = 10;
+  token.attr[0]    = TOKEN_ATTR_VERIFY_LENGTH
+                   | TOKEN_ATTR_VERIFY_HEX;
+
+  const int rc_tokenizer = input_tokenizer ((const u8 *) line_buf, line_len, &token);
+
+  if (rc_tokenizer != PARSER_OK) return (rc_tokenizer);
+
+  const u8 *hash_pos = token.buf[0];
+
+  digest[0] = hex_to_u32 (hash_pos +  0);
+  digest[1] = hex_to_u32 (hash_pos +  8);
+
+  if (hashconfig->opti_type & OPTI_TYPE_OPTIMIZED_KERNEL)
+  {
+    digest[0] -= MD5M_A;
+    digest[1] -= MD5M_B;
+  }
+
+  digest[1] &= 0x000000ff;
+
+  return (PARSER_OK);
+}
+
+int module_hash_encode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const void *digest_buf, MAYBE_UNUSED const salt_t *salt, MAYBE_UNUSED const void *esalt_buf, MAYBE_UNUSED const void *hook_salt_buf, MAYBE_UNUSED const hashinfo_t *hash_info, char *line_buf, MAYBE_UNUSED const int line_size)
+{
+  const u32 *digest = (const u32 *) digest_buf;
+
+  // we can not change anything in the original buffer, otherwise destroying sorting
+  // therefore create some local buffer
+
+  u32 tmp[2];
+
+  tmp[0] = digest[0];
+  tmp[1] = digest[1];
+
+  if (hashconfig->opti_type & OPTI_TYPE_OPTIMIZED_KERNEL)
+  {
+    tmp[0] += MD5M_A;
+    tmp[1] += MD5M_B;
+  }
+
+  u8 *out_buf = (u8 *) line_buf;
+
+  int out_len = 0;
+
+  u32_to_hex (tmp[0], out_buf + out_len); out_len += 8;
+  u32_to_hex (tmp[1], out_buf + out_len); out_len += 2;
+
+  return out_len;
+}
+
+void module_init (module_ctx_t *module_ctx)
+{
+  module_ctx->module_context_size             = MODULE_CONTEXT_SIZE_CURRENT;
+  module_ctx->module_interface_version        = MODULE_INTERFACE_VERSION_CURRENT;
+
+  module_ctx->module_attack_exec              = module_attack_exec;
+  module_ctx->module_benchmark_esalt          = MODULE_DEFAULT;
+  module_ctx->module_benchmark_hook_salt      = MODULE_DEFAULT;
+  module_ctx->module_benchmark_mask           = MODULE_DEFAULT;
+  module_ctx->module_benchmark_salt           = MODULE_DEFAULT;
+  module_ctx->module_build_plain_postprocess  = MODULE_DEFAULT;
+  module_ctx->module_deep_comp_kernel         = MODULE_DEFAULT;
+  module_ctx->module_dgst_pos0                = module_dgst_pos0;
+  module_ctx->module_dgst_pos1                = module_dgst_pos1;
+  module_ctx->module_dgst_pos2                = module_dgst_pos2;
+  module_ctx->module_dgst_pos3                = module_dgst_pos3;
+  module_ctx->module_dgst_size                = module_dgst_size;
+  module_ctx->module_dictstat_disable         = MODULE_DEFAULT;
+  module_ctx->module_esalt_size               = MODULE_DEFAULT;
+  module_ctx->module_extra_buffer_size        = MODULE_DEFAULT;
+  module_ctx->module_extra_tmp_size           = MODULE_DEFAULT;
+  module_ctx->module_forced_outfile_format    = MODULE_DEFAULT;
+  module_ctx->module_hash_binary_count        = MODULE_DEFAULT;
+  module_ctx->module_hash_binary_parse        = MODULE_DEFAULT;
+  module_ctx->module_hash_binary_save         = MODULE_DEFAULT;
+  module_ctx->module_hash_decode_potfile      = MODULE_DEFAULT;
+  module_ctx->module_hash_decode_zero_hash    = MODULE_DEFAULT;
+  module_ctx->module_hash_decode              = module_hash_decode;
+  module_ctx->module_hash_encode_status       = MODULE_DEFAULT;
+  module_ctx->module_hash_encode_potfile      = MODULE_DEFAULT;
+  module_ctx->module_hash_encode              = module_hash_encode;
+  module_ctx->module_hash_init_selftest       = MODULE_DEFAULT;
+  module_ctx->module_hash_mode                = MODULE_DEFAULT;
+  module_ctx->module_hash_category            = module_hash_category;
+  module_ctx->module_hash_name                = module_hash_name;
+  module_ctx->module_hashes_count_min         = MODULE_DEFAULT;
+  module_ctx->module_hashes_count_max         = MODULE_DEFAULT;
+  module_ctx->module_hlfmt_disable            = MODULE_DEFAULT;
+  module_ctx->module_hook_extra_param_size    = MODULE_DEFAULT;
+  module_ctx->module_hook_extra_param_init    = MODULE_DEFAULT;
+  module_ctx->module_hook_extra_param_term    = MODULE_DEFAULT;
+  module_ctx->module_hook12                   = MODULE_DEFAULT;
+  module_ctx->module_hook23                   = MODULE_DEFAULT;
+  module_ctx->module_hook_salt_size           = MODULE_DEFAULT;
+  module_ctx->module_hook_size                = MODULE_DEFAULT;
+  module_ctx->module_jit_build_options        = MODULE_DEFAULT;
+  module_ctx->module_jit_cache_disable        = MODULE_DEFAULT;
+  module_ctx->module_kernel_accel_max         = MODULE_DEFAULT;
+  module_ctx->module_kernel_accel_min         = MODULE_DEFAULT;
+  module_ctx->module_kernel_loops_max         = MODULE_DEFAULT;
+  module_ctx->module_kernel_loops_min         = MODULE_DEFAULT;
+  module_ctx->module_kernel_threads_max       = MODULE_DEFAULT;
+  module_ctx->module_kernel_threads_min       = MODULE_DEFAULT;
+  module_ctx->module_kern_type                = module_kern_type;
+  module_ctx->module_kern_type_dynamic        = MODULE_DEFAULT;
+  module_ctx->module_opti_type                = module_opti_type;
+  module_ctx->module_opts_type                = module_opts_type;
+  module_ctx->module_outfile_check_disable    = MODULE_DEFAULT;
+  module_ctx->module_outfile_check_nocomp     = MODULE_DEFAULT;
+  module_ctx->module_potfile_custom_check     = MODULE_DEFAULT;
+  module_ctx->module_potfile_disable          = MODULE_DEFAULT;
+  module_ctx->module_potfile_keep_all_hashes  = MODULE_DEFAULT;
+  module_ctx->module_pwdump_column            = MODULE_DEFAULT;
+  module_ctx->module_pw_max                   = MODULE_DEFAULT;
+  module_ctx->module_pw_min                   = MODULE_DEFAULT;
+  module_ctx->module_salt_max                 = MODULE_DEFAULT;
+  module_ctx->module_salt_min                 = MODULE_DEFAULT;
+  module_ctx->module_salt_type                = module_salt_type;
+  module_ctx->module_separator                = MODULE_DEFAULT;
+  module_ctx->module_st_hash                  = module_st_hash;
+  module_ctx->module_st_pass                  = module_st_pass;
+  module_ctx->module_tmp_size                 = MODULE_DEFAULT;
+  module_ctx->module_unstable_warning         = MODULE_DEFAULT;
+  module_ctx->module_warmup_disable           = MODULE_DEFAULT;
+}
diff --git a/src/modules/module_24800.c b/src/modules/module_24800.c
new file mode 100644
index 000000000..f7abd0acf
--- /dev/null
+++ b/src/modules/module_24800.c
@@ -0,0 +1,186 @@
+/**
+ * Author......: See docs/credits.txt
+ * License.....: MIT
+ */
+
+#include "common.h"
+#include "types.h"
+#include "modules.h"
+#include "bitops.h"
+#include "convert.h"
+#include "shared.h"
+
+static const u32   ATTACK_EXEC    = ATTACK_EXEC_INSIDE_KERNEL;
+static const u32   DGST_POS0      = 3;
+static const u32   DGST_POS1      = 4;
+static const u32   DGST_POS2      = 2;
+static const u32   DGST_POS3      = 1;
+static const u32   DGST_SIZE      = DGST_SIZE_4_5;
+static const u32   HASH_CATEGORY  = HASH_CATEGORY_FORUM_SOFTWARE;
+static const char *HASH_NAME      = "Umbraco HMAC-SHA1";
+static const u64   KERN_TYPE      = 24800;
+static const u32   OPTI_TYPE      = OPTI_TYPE_ZERO_BYTE
+                                  | OPTI_TYPE_NOT_ITERATED;
+static const u64   OPTS_TYPE      = OPTS_TYPE_PT_GENERATE_BE
+                                  | OPTS_TYPE_PT_UTF16LE;
+static const u32   SALT_TYPE      = SALT_TYPE_EMBEDDED;
+static const char *ST_PASS        = "hashcat";
+static const char *ST_HASH        = "8uigXlGMNI7BzwLCJlDbcKR2FP4=";
+
+u32         module_attack_exec    (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return ATTACK_EXEC;     }
+u32         module_dgst_pos0      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return DGST_POS0;       }
+u32         module_dgst_pos1      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return DGST_POS1;       }
+u32         module_dgst_pos2      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return DGST_POS2;       }
+u32         module_dgst_pos3      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return DGST_POS3;       }
+u32         module_dgst_size      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return DGST_SIZE;       }
+u32         module_hash_category  (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return HASH_CATEGORY;   }
+const char *module_hash_name      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return HASH_NAME;       }
+u64         module_kern_type      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return KERN_TYPE;       }
+u32         module_opti_type      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return OPTI_TYPE;       }
+u64         module_opts_type      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return OPTS_TYPE;       }
+u32         module_salt_type      (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return SALT_TYPE;       }
+const char *module_st_hash        (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return ST_HASH;         }
+const char *module_st_pass        (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return ST_PASS;         }
+
+int module_hash_decode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED void *digest_buf, MAYBE_UNUSED salt_t *salt, MAYBE_UNUSED void *esalt_buf, MAYBE_UNUSED void *hook_salt_buf, MAYBE_UNUSED hashinfo_t *hash_info, const char *line_buf, MAYBE_UNUSED const int line_len)
+{
+  u32 *digest = (u32 *) digest_buf;
+
+  token_t token;
+
+  token.token_cnt  = 1;
+
+  token.len_min[0] = 28;
+  token.len_max[0] = 28;
+  token.attr[0]    = TOKEN_ATTR_VERIFY_LENGTH
+                   | TOKEN_ATTR_VERIFY_BASE64A;
+
+  const int rc_tokenizer = input_tokenizer ((const u8 *) line_buf, line_len, &token);
+
+  if (rc_tokenizer != PARSER_OK) return (rc_tokenizer);
+
+  const u8 *hash_pos = token.buf[0];
+  const int hash_len = token.len[0];
+
+  u8 tmp_buf[32] = { 0 };
+
+  const int decoded_len = base64_decode (base64_to_int, hash_pos, hash_len, tmp_buf);
+
+  if (decoded_len != 20) return (PARSER_HASH_LENGTH);
+
+  memcpy (digest, tmp_buf, 20);
+
+  digest[0] = byte_swap_32 (digest[0]);
+  digest[1] = byte_swap_32 (digest[1]);
+  digest[2] = byte_swap_32 (digest[2]);
+  digest[3] = byte_swap_32 (digest[3]);
+  digest[4] = byte_swap_32 (digest[4]);
+
+  return (PARSER_OK);
+}
+
+int module_hash_encode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const void *digest_buf, MAYBE_UNUSED const salt_t *salt, MAYBE_UNUSED const void *esalt_buf, MAYBE_UNUSED const void *hook_salt_buf, MAYBE_UNUSED const hashinfo_t *hash_info, char *line_buf, MAYBE_UNUSED const int line_size)
+{
+  const u32 *digest = (const u32 *) digest_buf;
+
+  // we can not change anything in the original buffer, otherwise destroying sorting
+  // therefore create some local buffer
+
+  u32 tmp[5];
+
+  tmp[0] = digest[0];
+  tmp[1] = digest[1];
+  tmp[2] = digest[2];
+  tmp[3] = digest[3];
+  tmp[4] = digest[4];
+
+  tmp[0] = byte_swap_32 (tmp[0]);
+  tmp[1] = byte_swap_32 (tmp[1]);
+  tmp[2] = byte_swap_32 (tmp[2]);
+  tmp[3] = byte_swap_32 (tmp[3]);
+  tmp[4] = byte_swap_32 (tmp[4]);
+
+  u8 ptr_plain[100] = { 0 };
+
+  base64_encode (int_to_base64, (const u8 *) tmp, 20, (u8 *) ptr_plain);
+
+  const int out_len = snprintf (line_buf, line_size, "%s", (char *) ptr_plain);
+
+  return out_len;
+}
+
+void module_init (module_ctx_t *module_ctx)
+{
+  module_ctx->module_context_size             = MODULE_CONTEXT_SIZE_CURRENT;
+  module_ctx->module_interface_version        = MODULE_INTERFACE_VERSION_CURRENT;
+
+  module_ctx->module_attack_exec              = module_attack_exec;
+  module_ctx->module_benchmark_esalt          = MODULE_DEFAULT;
+  module_ctx->module_benchmark_hook_salt      = MODULE_DEFAULT;
+  module_ctx->module_benchmark_mask           = MODULE_DEFAULT;
+  module_ctx->module_benchmark_salt           = MODULE_DEFAULT;
+  module_ctx->module_build_plain_postprocess  = MODULE_DEFAULT;
+  module_ctx->module_deep_comp_kernel         = MODULE_DEFAULT;
+  module_ctx->module_dgst_pos0                = module_dgst_pos0;
+  module_ctx->module_dgst_pos1                = module_dgst_pos1;
+  module_ctx->module_dgst_pos2                = module_dgst_pos2;
+  module_ctx->module_dgst_pos3                = module_dgst_pos3;
+  module_ctx->module_dgst_size                = module_dgst_size;
+  module_ctx->module_dictstat_disable         = MODULE_DEFAULT;
+  module_ctx->module_esalt_size               = MODULE_DEFAULT;
+  module_ctx->module_extra_buffer_size        = MODULE_DEFAULT;
+  module_ctx->module_extra_tmp_size           = MODULE_DEFAULT;
+  module_ctx->module_forced_outfile_format    = MODULE_DEFAULT;
+  module_ctx->module_hash_binary_count        = MODULE_DEFAULT;
+  module_ctx->module_hash_binary_parse        = MODULE_DEFAULT;
+  module_ctx->module_hash_binary_save         = MODULE_DEFAULT;
+  module_ctx->module_hash_decode_potfile      = MODULE_DEFAULT;
+  module_ctx->module_hash_decode_zero_hash    = MODULE_DEFAULT;
+  module_ctx->module_hash_decode              = module_hash_decode;
+  module_ctx->module_hash_encode_status       = MODULE_DEFAULT;
+  module_ctx->module_hash_encode_potfile      = MODULE_DEFAULT;
+  module_ctx->module_hash_encode              = module_hash_encode;
+  module_ctx->module_hash_init_selftest       = MODULE_DEFAULT;
+  module_ctx->module_hash_mode                = MODULE_DEFAULT;
+  module_ctx->module_hash_category            = module_hash_category;
+  module_ctx->module_hash_name                = module_hash_name;
+  module_ctx->module_hashes_count_min         = MODULE_DEFAULT;
+  module_ctx->module_hashes_count_max         = MODULE_DEFAULT;
+  module_ctx->module_hlfmt_disable            = MODULE_DEFAULT;
+  module_ctx->module_hook_extra_param_size    = MODULE_DEFAULT;
+  module_ctx->module_hook_extra_param_init    = MODULE_DEFAULT;
+  module_ctx->module_hook_extra_param_term    = MODULE_DEFAULT;
+  module_ctx->module_hook12                   = MODULE_DEFAULT;
+  module_ctx->module_hook23                   = MODULE_DEFAULT;
+  module_ctx->module_hook_salt_size           = MODULE_DEFAULT;
+  module_ctx->module_hook_size                = MODULE_DEFAULT;
+  module_ctx->module_jit_build_options        = MODULE_DEFAULT;
+  module_ctx->module_jit_cache_disable        = MODULE_DEFAULT;
+  module_ctx->module_kernel_accel_max         = MODULE_DEFAULT;
+  module_ctx->module_kernel_accel_min         = MODULE_DEFAULT;
+  module_ctx->module_kernel_loops_max         = MODULE_DEFAULT;
+  module_ctx->module_kernel_loops_min         = MODULE_DEFAULT;
+  module_ctx->module_kernel_threads_max       = MODULE_DEFAULT;
+  module_ctx->module_kernel_threads_min       = MODULE_DEFAULT;
+  module_ctx->module_kern_type                = module_kern_type;
+  module_ctx->module_kern_type_dynamic        = MODULE_DEFAULT;
+  module_ctx->module_opti_type                = module_opti_type;
+  module_ctx->module_opts_type                = module_opts_type;
+  module_ctx->module_outfile_check_disable    = MODULE_DEFAULT;
+  module_ctx->module_outfile_check_nocomp     = MODULE_DEFAULT;
+  module_ctx->module_potfile_custom_check     = MODULE_DEFAULT;
+  module_ctx->module_potfile_disable          = MODULE_DEFAULT;
+  module_ctx->module_potfile_keep_all_hashes  = MODULE_DEFAULT;
+  module_ctx->module_pwdump_column            = MODULE_DEFAULT;
+  module_ctx->module_pw_max                   = MODULE_DEFAULT;
+  module_ctx->module_pw_min                   = MODULE_DEFAULT;
+  module_ctx->module_salt_max                 = MODULE_DEFAULT;
+  module_ctx->module_salt_min                 = MODULE_DEFAULT;
+  module_ctx->module_salt_type                = module_salt_type;
+  module_ctx->module_separator                = MODULE_DEFAULT;
+  module_ctx->module_st_hash                  = module_st_hash;
+  module_ctx->module_st_pass                  = module_st_pass;
+  module_ctx->module_tmp_size                 = MODULE_DEFAULT;
+  module_ctx->module_unstable_warning         = MODULE_DEFAULT;
+  module_ctx->module_warmup_disable           = MODULE_DEFAULT;
+}
diff --git a/src/modules/module_24900.c b/src/modules/module_24900.c
index 436060dc3..31a218c82 100644
--- a/src/modules/module_24900.c
+++ b/src/modules/module_24900.c
@@ -21,7 +21,6 @@ static const char *HASH_NAME      = "Dahua Authentication MD5";
 static const u64   KERN_TYPE      = 24900;
 static const u32   OPTI_TYPE      = OPTI_TYPE_ZERO_BYTE
                                   | OPTI_TYPE_PRECOMPUTE_INIT
-                                  | OPTI_TYPE_MEET_IN_MIDDLE
                                   | OPTI_TYPE_NOT_ITERATED
                                   | OPTI_TYPE_NOT_SALTED
                                   | OPTI_TYPE_RAW_HASH;
@@ -47,6 +46,42 @@ u32         module_salt_type      (MAYBE_UNUSED const hashconfig_t *hashconfig,
 const char *module_st_hash        (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return ST_HASH;         }
 const char *module_st_pass        (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return ST_PASS;         }
 
+u32 dahua_decode (const u32 in)
+{
+  if (in >= 'a')
+  {
+    return (in - 61);
+  }
+  else if (in >= 'A')
+  {
+    return (in - 55);
+  }
+  else
+  {
+    return (in - 48);
+  }
+
+  return -1;
+}
+
+u32 dahua_encode (const u32 in)
+{
+  if (in < 10)
+  {
+    return (in + 48);
+  }
+  else if (in < 36)
+  {
+    return (in + 55);
+  }
+  else
+  {
+    return (in + 61);
+  }
+
+  return -1;
+}
+
 int module_hash_decode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED void *digest_buf, MAYBE_UNUSED salt_t *salt, MAYBE_UNUSED void *esalt_buf, MAYBE_UNUSED void *hook_salt_buf, MAYBE_UNUSED hashinfo_t *hash_info, const char *line_buf, MAYBE_UNUSED const int line_len)
 {
   u32 *digest = (u32 *) digest_buf;
@@ -62,17 +97,22 @@ int module_hash_decode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE
   const int rc_tokenizer = input_tokenizer ((const u8 *) line_buf, line_len, &token);
 
   if (rc_tokenizer != PARSER_OK) return (rc_tokenizer);
-  
-  u8 temp_hex_buf[17] = { 0 };
 
   const u8 *hash_pos = token.buf[0];
 
-  hex_encode ((u8 *) hash_pos, 8, temp_hex_buf);
+  const u32 a0 = dahua_decode (hash_pos[0]);
+  const u32 a1 = dahua_decode (hash_pos[1]);
+  const u32 b0 = dahua_decode (hash_pos[2]);
+  const u32 b1 = dahua_decode (hash_pos[3]);
+  const u32 c0 = dahua_decode (hash_pos[4]);
+  const u32 c1 = dahua_decode (hash_pos[5]);
+  const u32 d0 = dahua_decode (hash_pos[6]);
+  const u32 d1 = dahua_decode (hash_pos[7]);
 
-  digest[0] = hex_to_u32 (temp_hex_buf +  0);
-  digest[1] = hex_to_u32 (temp_hex_buf +  8);
-  digest[2] = 0;
-  digest[3] = 0;
+  digest[0] = (a0 << 0) | (a1 << 8);
+  digest[1] = (b0 << 0) | (b1 << 8);
+  digest[2] = (c0 << 0) | (c1 << 8);
+  digest[3] = (d0 << 0) | (d1 << 8);
 
   return (PARSER_OK);
 }
@@ -81,24 +121,16 @@ int module_hash_encode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE
 {
   const u32 *digest = (const u32 *) digest_buf;
 
-  // we can not change anything in the original buffer, otherwise destroying sorting
-  // therefore create some local buffer
-
-  u32 tmp[4];
-
-  tmp[0] = digest[0];
-  tmp[1] = digest[1];
-  tmp[2] = 0;
-  tmp[3] = 0;
-
   u8 *out_buf = (u8 *) line_buf;
 
-  u8 ht_buf[17] = { 0 };
-
-  u32_to_hex (tmp[0], ht_buf +  0);
-  u32_to_hex (tmp[1], ht_buf +  8);
-
-  hex_decode (ht_buf, 16, (u8 *) out_buf);
+  out_buf[0] = (u8) dahua_encode ((digest[0] >> 0) & 0xff);
+  out_buf[1] = (u8) dahua_encode ((digest[0] >> 8) & 0xff);
+  out_buf[2] = (u8) dahua_encode ((digest[1] >> 0) & 0xff);
+  out_buf[3] = (u8) dahua_encode ((digest[1] >> 8) & 0xff);
+  out_buf[4] = (u8) dahua_encode ((digest[2] >> 0) & 0xff);
+  out_buf[5] = (u8) dahua_encode ((digest[2] >> 8) & 0xff);
+  out_buf[6] = (u8) dahua_encode ((digest[3] >> 0) & 0xff);
+  out_buf[7] = (u8) dahua_encode ((digest[3] >> 8) & 0xff);
 
   const int out_len = 8;
 
diff --git a/src/usage.c b/src/usage.c
index 0b9ad03fc..87a58c56e 100644
--- a/src/usage.c
+++ b/src/usage.c
@@ -36,7 +36,7 @@ static const char *const USAGE_BIG_PRE_HASHMODES[] =
   "     --hex-wordlist             |      | Assume words in wordlist are given in hex            |",
   "     --force                    |      | Ignore warnings                                      |",
   "     --status                   |      | Enable automatic update of the status screen         |",
-  "     --status-json              |      | Enable JSON format for status ouput                  |",
+  "     --status-json              |      | Enable JSON format for status output                 |",
   "     --status-timer             | Num  | Sets seconds between status screen updates to X      | --status-timer=1",
   "     --stdin-timeout-abort      | Num  | Abort if there is no input from stdin for X seconds  | --stdin-timeout-abort=300",
   "     --machine-readable         |      | Display the status view in a machine-readable format |",
diff --git a/tools/sqlcipher2hashcat.pl b/tools/sqlcipher2hashcat.pl
new file mode 100755
index 000000000..930523eff
--- /dev/null
+++ b/tools/sqlcipher2hashcat.pl
@@ -0,0 +1,75 @@
+#!/usr/bin/env perl
+
+##
+## Author......: See docs/credits.txt
+## License.....: MIT
+##
+
+# In a first version I wrote a kernel that followed the original sqlcipher scheme which uses a MAC to verify the integrity (and therefore we knew we had guessed the correct password).
+# But it turns out it's much easier to exploit the sqlite header format, which guarantees 20 zero bytes starting from offset 72.
+# See: https://www.sqlite.org/fileformat.html
+# The advantage is the user doesn't need to guess the MAC hash type and/or pagesize (in case it they customized).
+# The user still needs to know the KDF hash type and iteration count, but they sqlcipher v3 and v4 come with a default for these.
+# We'll check only 12 of 16 bytes from the encrypted block as an optimization so we only need to decrypt one block.
+# Another optimization is that since the scheme uses CBC we do not need to find the correct position of the IV.
+# This position is depending on the pagesize and the KDF hash type (which could be customized).
+# As an alternative, or in case the sqlite header changes, we could also use entropy test.
+# -atom
+
+use strict;
+use warnings;
+
+if (scalar (@ARGV) < 2)
+{
+  print "usage: $0 encrypted.db preset [hash] [iteration]\n\n";
+  print "preset 1 = SQLCIPHER v3\n";
+  print "preset 2 = SQLCIPHER v4\n";
+  print "preset 3 = CUSTOM, please specify hash type (1 = SHA1, 2 = SHA256, 3 = SHA512) and iteration count\n";
+
+  exit -1;
+}
+
+my $db     = $ARGV[0];
+my $preset = $ARGV[1];
+
+my $type = 0;
+my $iter = 0;
+
+if ($preset == 1)
+{
+  $type = 1;
+  $iter = 64000;
+}
+elsif ($preset == 2)
+{
+  $type = 3;
+  $iter = 256000;
+}
+elsif ($preset == 3)
+{
+  $type = $ARGV[2];
+  $iter = $ARGV[3];
+}
+else
+{
+  die "Invalid preset\n";
+}
+
+open (IN, $db) or die ("$db: $!\n");
+
+binmode (IN);
+
+my $data;
+
+if (read (IN, $data, 96) != 96)
+{
+  die "ERROR: Couldn't read data from the file. Maybe incorrect file format?\n";
+}
+
+close (IN);
+
+my $salt = substr ($data,  0, 16);
+my $iv   = substr ($data, 64, 16);
+my $enc  = substr ($data, 80, 16);
+
+printf ("SQLCIPHER*%d*%d*%s*%s*%s\n", $type, $iter, unpack ("H*", $salt), unpack ("H*", $iv), unpack ("H*", $enc));
diff --git a/tools/test_modules/m24600.pm b/tools/test_modules/m24600.pm
new file mode 100644
index 000000000..91954f551
--- /dev/null
+++ b/tools/test_modules/m24600.pm
@@ -0,0 +1,135 @@
+#!/usr/bin/env perl
+
+##
+## Author......: See docs/credits.txt
+## License.....: MIT
+##
+
+use strict;
+use warnings;
+
+use Crypt::PBKDF2;
+use Crypt::CBC;
+
+sub module_constraints { [[0, 256], [32, 32], [-1, -1], [-1, -1], [-1, -1]] }
+
+sub module_generate_hash
+{
+  my $word = shift;
+  my $salt = shift;
+  my $type = shift // 1; #random_number (1, 3);
+  my $iter = shift // random_number (10000, 20000);
+  my $iv   = shift // random_hex_string (32);
+  my $enc  = shift;
+
+  my $kdf;
+
+  if ($type == 1)
+  {
+    $kdf = Crypt::PBKDF2->new
+    (
+      hash_class => 'HMACSHA1',
+      iterations => $iter,
+      output_len => 32
+    );
+  }
+  elsif ($type == 2)
+  {
+    $kdf = Crypt::PBKDF2->new
+    (
+      hasher     => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 256),
+      iterations => $iter,
+      output_len => 32
+    );
+  }
+  elsif ($type == 3)
+  {
+    $kdf = Crypt::PBKDF2->new
+    (
+      hasher     => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 512),
+      iterations => $iter,
+      output_len => 32
+    );
+  }
+
+  my $salt_bin = pack ("H*", $salt);
+
+  my $key = $kdf->PBKDF2 ($salt_bin, $word);
+
+  my $iv_bin = pack ("H*", $iv);
+
+  my $data;
+
+  if (defined $enc)
+  {
+    my $aes_cbc = Crypt::CBC->new ({
+      cipher      => "Crypt::Rijndael",
+      iv          => $iv_bin,
+      key         => $key,
+      keysize     => 32,
+      literal_key => 1,
+      header      => "none",
+      padding     => "none"
+    });
+
+    my $enc_bin = pack ("H*", $enc);
+
+    $data = $aes_cbc->decrypt ($enc_bin);
+
+    if (substr ($data, 0, 12) ne "\x00" x 12)
+    {
+      $data = "\xff" x 16;
+    }
+  }
+  else
+  {
+    $data = "\x00" x 16;
+  }
+
+  my $aes_cbc = Crypt::CBC->new ({
+    cipher      => "Crypt::Rijndael",
+    iv          => $iv_bin,
+    key         => $key,
+    keysize     => 32,
+    literal_key => 1,
+    header      => "none",
+    padding     => "none"
+  });
+
+  my $enc_bin = $aes_cbc->encrypt ($data);
+
+  my $hash = sprintf ("SQLCIPHER*%d*%d*%s*%s*%s", $type, $iter, unpack ("H*", $salt_bin), unpack ("H*", $iv_bin), unpack ("H*", $enc_bin));
+
+  return $hash;
+}
+
+sub module_verify_hash
+{
+  my $line = shift;
+
+  my $idx = index ($line, ':');
+
+  return unless $idx >= 0;
+
+  my $hash = substr ($line, 0, $idx);
+  my $word = substr ($line, $idx + 1);
+
+  return unless substr ($hash, 0, 9) eq 'SQLCIPHER';
+
+  my ($signature, $type, $iter, $salt, $iv, $data) = split '\*', $hash;
+
+  return unless defined $signature;
+  return unless defined $type;
+  return unless defined $iter;
+  return unless defined $salt;
+  return unless defined $iv;
+  return unless defined $data;
+
+  my $word_packed = pack_if_HEX_notation ($word);
+
+  my $new_hash = module_generate_hash ($word_packed, $salt, $type, $iter, $iv, $data);
+
+  return ($new_hash, $word);
+}
+
+1;
diff --git a/tools/test_modules/m24700.pm b/tools/test_modules/m24700.pm
new file mode 100644
index 000000000..47806b512
--- /dev/null
+++ b/tools/test_modules/m24700.pm
@@ -0,0 +1,49 @@
+#!/usr/bin/env perl
+
+##
+## Author......: See docs/credits.txt
+## License.....: MIT
+##
+
+use strict;
+use warnings;
+
+use Digest::MD5 qw (md5_hex);
+use Digest::MD5 qw (md5);
+
+sub module_constraints { [[0, 256], [-1, -1], [0, 55], [-1, -1], [-1, -1]] }
+
+sub module_generate_hash
+{
+  my $word = shift;
+
+  my $digest1 = md5 ($word);
+
+  my $digest1_sub = substr ($digest1, 0, 5);
+
+  my $digest2 = md5 ($digest1_sub);
+
+  my $digest2_sub = substr ($digest2, 0, 5);
+
+  my $hash = sprintf ("%s", unpack ("H*", $digest2_sub));
+
+  return $hash;
+}
+
+sub module_verify_hash
+{
+  my $line = shift;
+
+  my ($hash, $word) = split (':', $line);
+
+  return unless defined $hash;
+  return unless defined $word;
+
+  my $word_packed = pack_if_HEX_notation ($word);
+
+  my $new_hash = module_generate_hash ($word_packed);
+
+  return ($new_hash, $word);
+}
+
+1;
diff --git a/tools/test_modules/m24800.pm b/tools/test_modules/m24800.pm
new file mode 100644
index 000000000..9d63a2c9c
--- /dev/null
+++ b/tools/test_modules/m24800.pm
@@ -0,0 +1,47 @@
+#!/usr/bin/env perl
+
+##
+## Author......: See docs/credits.txt
+## License.....: MIT
+##
+
+use strict;
+use warnings;
+
+use Digest::SHA1 qw (sha1);
+use Digest::HMAC qw (hmac hmac_hex);
+use Encode qw (encode decode);
+use MIME::Base64;
+
+sub module_constraints { [[0, 256], [0, 256], [0, 27], [0, 27], [0, 27]] }
+
+sub module_generate_hash
+{
+  my $word = shift;
+
+  my $unicode_word = encode ("UTF-16LE", $word);
+
+  my $digest = hmac ($unicode_word, $unicode_word, \&sha1, 64);
+
+  my $hash = sprintf ("%s", encode_base64 ($digest, ""));
+
+  return $hash;
+}
+
+sub module_verify_hash
+{
+  my $line = shift;
+
+  my ($hash, $word) = split (':', $line);
+
+  return unless defined $hash;
+  return unless defined $word;
+
+  my $word_packed = pack_if_HEX_notation ($word);
+
+  my $new_hash = module_generate_hash ($word_packed);
+
+  return ($new_hash, $word);
+}
+
+1;
diff --git a/tools/test_modules/m24900.pm b/tools/test_modules/m24900.pm
new file mode 100644
index 000000000..4386c951e
--- /dev/null
+++ b/tools/test_modules/m24900.pm
@@ -0,0 +1,58 @@
+#!/usr/bin/env perl
+
+##
+## Author......: See docs/credits.txt
+## License.....: MIT
+##
+
+use strict;
+use warnings;
+use MIME::Base64 qw (encode_base64 decode_base64);
+
+use Digest::MD5 qw (md5);
+
+sub module_constraints { [[0, 256], [-1, -1], [0, 55], [-1, -1], [-1, -1]] }
+
+my $itoa62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+sub module_generate_hash
+{
+  my $word = shift;
+
+  my $digest = md5 ($word);
+
+  my @chksum;
+
+  for (my $i = 0, my $j = 0; $i < 16; $i += 2, $j += 1)
+  {
+    $chksum[$j] = (ord (substr ($digest, $i + 0, 1)) + ord (substr ($digest, $i + 1, 1))) % 62;
+
+printf ("%d\n", $chksum[$j]);
+
+    $chksum[$j] = substr ($itoa62, $chksum[$j], 1);
+  }
+
+  my $res = join "", @chksum;
+
+  my $hash = sprintf ("%s", $res);
+
+  return $hash;
+}
+
+sub module_verify_hash
+{
+  my $line = shift;
+
+  my ($hash, $word) = split (':', $line);
+
+  return unless defined $hash;
+  return unless defined $word;
+
+  my $word_packed = pack_if_HEX_notation ($word);
+
+  my $new_hash = module_generate_hash ($word_packed);
+
+  return ($new_hash, $word);
+}
+
+1;