//+------------------------------------------------------------------+ //| SHA3.mqh | //| Copyright 2026, Niquel Mendoza | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, Niquel Mendoza" #property link "https://www.mql5.com" #property strict #ifndef CRYPTOBYLEO_SRC_HASH_SHA3_MQH #define CRYPTOBYLEO_SRC_HASH_SHA3_MQH //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include "Base.mqh" //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ //--- #define SHA3_DELIM_SHA3 (0x06) #define SHA3_DELIM_SHAKE (0x1F) //--- #define SHA3_256_OUT_BSIZE (32) #define SHA3_256_BLOCK_SIZE (136) //--- #define SHA3_512_OUT_BSIZE (64) #define SHA3_512_BLOCK_SIZE (72) //--- #define SHA3_384_OUT_BSIZE (48) #define SHA3_384_BLOCK_SIZE (104) //--- #define SHA3_SHAKE_128_BLOCK_SIZE (168) #define SHA3_SHAKE_256_BLOCK_SIZE (136) //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ namespace TSN { //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #define SHA3_LOADINLINE(idx) \ s[idx] ^= ((uint64_t)in[pos++]) | \ ((uint64_t)in[pos++] << 8) | \ ((uint64_t)in[pos++] << 16) | \ ((uint64_t)in[pos++] << 24) | \ ((uint64_t)in[pos++] << 32) | \ ((uint64_t)in[pos++] << 40) | \ ((uint64_t)in[pos++] << 48) | \ ((uint64_t)in[pos++] << 56); //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CCryptoHashSHA3 { private: static void SHA3_KECCAK_F(ulong &s[]); public: CCryptoHashSHA3(void) {} ~CCryptoHashSHA3(void) {} //--- union SHA3_UN { uchar block[200]; ulong uv[25]; }; //--- Por limitaciones del compilador de que no se permite tempaltes medio raras // en static class lo hare inline //--- // TChunkBytes = tamaño del bloquje en bytes que se procesar en cada it // ins= tmaño del inpunt (in) // in= input // out=salida // outl= tamaño de salida template static void SHA3_HASH(const uchar &in[], int ins, uchar &out[], int outl, int o_s) { //--- Iniciales ulong s[25] = {0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL }; const int rho[25] = {0, 1, 62, 28, 27, 36, 44, 6, 55, 20, 3, 10, 43, 25, 39, 41, 45, 15, 21, 8, 18, 2, 61, 56, 14}; const int pi[25] = {0, 10, 20, 5, 15, 16, 1, 11, 21, 6, 7, 17, 2, 12, 22, 23, 8, 18, 3, 13, 14, 24, 9, 19, 4}; const ulong rc[24] = { 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 }; //--- paso 1 absorcion int pos = 0; while(ins - pos >= sizeof(TChunkBytes)) { //---- carga inline (72 bytes iniciales el minimo comun entre todos.. de ahi algunos cargan mas..) SHA3_LOADINLINE(0) SHA3_LOADINLINE(1) SHA3_LOADINLINE(2) SHA3_LOADINLINE(3) SHA3_LOADINLINE(4) SHA3_LOADINLINE(5) SHA3_LOADINLINE(6) SHA3_LOADINLINE(7) SHA3_LOADINLINE(8) //---- carga manual for(int idx = 9; idx < (sizeof(TChunkBytes) >> 3); idx++) { s[idx] ^= ((uint64_t)in[pos++]) | ((uint64_t)in[pos++] << 8) | ((uint64_t)in[pos++] << 16) | ((uint64_t)in[pos++] << 24) | ((uint64_t)in[pos++] << 32) | ((uint64_t)in[pos++] << 40) | ((uint64_t)in[pos++] << 48) | ((uint64_t)in[pos++] << 56); } //--- // HOT PATH inline aqui mismo //------- statart of mixing // Nuestro "valor" en el cual operamos.. /* mapa= 5 filas 5 columnas y cada valor es un lane de 64 bits */ //--- Temp ulong c[5], d[5]; ulong b[25]; //--- Rondas. for(int r = 0; r < 24; r++) { //--- theta /* wiki Calcula la paridad de cada una de las 5 w (320, cuando w = 64 ) columnas de 5 bits y realiza la operación OR exclusiva con dos columnas cercanas siguiendo un patrón regular. Para ser precisos, a [ i ][  j ][ k ] ← a [ i ][  j ][ k ] ⊕ paridad(a[0...4][ j -1][ k ]) ⊕ paridad(a[0...4][ j +1][ k −1] ) */ // Por cada columna /*for(int x = 0; x < 5; x++) c[x] = s[x] ^ s[x + 5] ^ s[x + 10] ^ s[x + 15] ^ s[x + 20]; */ // Denserollado: c[0] = s[0] ^ s[5] ^ s[10] ^ s[15] ^ s[20]; c[1] = s[1] ^ s[6] ^ s[11] ^ s[16] ^ s[21]; c[2] = s[2] ^ s[7] ^ s[12] ^ s[17] ^ s[22]; c[3] = s[3] ^ s[8] ^ s[13] ^ s[18] ^ s[23]; c[4] = s[4] ^ s[9] ^ s[14] ^ s[19] ^ s[24]; // Final //for(int x = 0; x < 5; x++) /*{ const ulong cr = c[(x + 1) % 5]; d[x] = c[(x + 4) % 5] ^ ((cr << 1) | (cr >> 63)); }*/ // Denserollado { const ulong cr = c[1]; d[0] = c[4] ^ ((cr << 1) | (cr >> 63)); } { const ulong cr = c[2]; d[1] = c[0] ^ ((cr << 1) | (cr >> 63)); } { const ulong cr = c[3]; d[2] = c[1] ^ ((cr << 1) | (cr >> 63)); } { const ulong cr = c[4]; d[3] = c[2] ^ ((cr << 1) | (cr >> 63)); } { const ulong cr = c[0]; d[4] = c[3] ^ ((cr << 1) | (cr >> 63)); } // unrrolled s[0] ^= d[0]; s[1] ^= d[1]; s[2] ^= d[2]; s[3] ^= d[3]; s[4] ^= d[4]; s[5] ^= d[0]; s[6] ^= d[1]; s[7] ^= d[2]; s[8] ^= d[3]; s[9] ^= d[4]; s[10] ^= d[0]; s[11] ^= d[1]; s[12] ^= d[2]; s[13] ^= d[3]; s[14] ^= d[4]; s[15] ^= d[0]; s[16] ^= d[1]; s[17] ^= d[2]; s[18] ^= d[3]; s[19] ^= d[4]; s[20] ^= d[0]; s[21] ^= d[1]; s[22] ^= d[2]; s[23] ^= d[3]; s[24] ^= d[4]; //--- RHO+PI for(int i = 0; i < 25; i++) { /* Gire bit a bit cada una de las 25 palabras por un número triangular diferente 0, 1, 3, 6, 10, 15, .... (rho[]) Para ser precisos, a [0][0] no se rota, y para todo 0 ≤ t < 24 , a [ i ][  j ][ k ] ← a [ i ][  j ][ k −( t +1)( t +2)/2] , donde */ const int n = rho[i]; b[pi[i]] = (n == 0) ? s[i] : ((s[i] << n) | (s[i] >> (64 - n))); } //--- CHI fila a fila for(int y = 0; y < 5; y++) { /* Combinación bit a bit a lo largo de las filas, usando x ← x ⊕ (¬ y & z ) . Para ser precisos, a [ i ][  j ][ k ] ← a [ i ][  j ][ k ] ⊕ (¬ a [ i ][  j + 1 ][ k ] &a a [ i ][  j + 2 ][ k ]) . Esta es la única operación no lineal en SHA-3. */ //--- ulong row0 = b[5 * y], row1 = b[1 + 5 * y], row2 = b[2 + 5 * y], row3 = b[3 + 5 * y], row4 = b[4 + 5 * y]; //--- s[5 * y] = row0 ^ ((~row1) & row2); s[1 + 5 * y] = row1 ^ ((~row2) & row3); s[2 + 5 * y] = row2 ^ ((~row3) & row4); s[3 + 5 * y] = row3 ^ ((~row4) & row0); s[4 + 5 * y] = row4 ^ ((~row0) & row1); } //--- iota s[0] ^= rc[r]; } //----- //------- end of mixing //pos += sizeof(TChunkBytes); } // Lo demas ya no inline dado que no da una ganancia sinficativa por lo visto // dado qeu se llama poco... //--- ultimo bloque parcial + padding (0x06 o 0x1F ... 0x80) SHA3_UN v; ArrayInitialize(v.block, 0); //--- const int rem = ins - pos; //--- for(int i = 0; i < rem; i++) v.block[i] = in[pos + i]; //--- v.block[rem] = sizeof(TDelimBytes); v.block[sizeof(TChunkBytes) - 1] |= 0x80; //--- Ahora lo que sobra.. const int fin = (sizeof(TChunkBytes) >> 3); for(int i = 0; i < fin; i++) { /*const ulong w = ((ulong)block[i]) | ((ulong)block[i + 1] << 8) | ((ulong)block[i + 2] << 16) | ((ulong)block[i + 3] << 24) | ((ulong)block[i + 4] << 32) | ((ulong)block[i + 5] << 40) | ((ulong)block[i + 6] << 48) | ((ulong)block[i + 7] << 56);*/ s[i] ^= v.uv[i]; } SHA3_KECCAK_F(s); //--- // Print("hola", sizeof(TDelimBytes)); if(sizeof(TDelimBytes) == SHA3_DELIM_SHA3) { const int fin = (outl >> 3); // / 8 for(int k = 0; k < fin;) { const ulong t = s[k++]; out[o_s++] = uchar(t); out[o_s++] = uchar(t >> 8); out[o_s++] = uchar(t >> 16); out[o_s++] = uchar(t >> 24); out[o_s++] = uchar(t >> 32); out[o_s++] = uchar(t >> 40); out[o_s++] = uchar(t >> 48); out[o_s++] = uchar(t >> 56); } } else // dinamico { outl += o_s; while(o_s < outl) { //--- int t = outl - o_s; // tomado if(t > sizeof(TChunkBytes)) t = sizeof(TChunkBytes); // clamp a lo maximo a tomar.. //--- for(int i = 0; i < t; i++) { // en que lane // const int w = ; // i / 8 const int sh = (i & 7) << 3; // i % 8 * 8 - cuanto demzpasmroes del lane de 64 desde cuando se mrpiza out[o_s + i] = (uchar)(s[i >> 3] >> sh); // escribimos } o_s += t; // aumentaos lo que ya tenemos //--- if(o_s < outl) // volvemos.. se requier mas de lo normal asi qeu aplicanos denuevo para la nueva salida SHA3_KECCAK_F(s); } } } //---- Especificos static __forceinline void SHA3_256(const uchar &in[], int ins, uchar &out[], const int o_s); static __forceinline void SHA3_384(const uchar &in[], int ins, uchar &out[], const int o_s); static __forceinline void SHA3_512(const uchar &in[], int ins, uchar &out[], const int o_s); static __forceinline void SHAKE128(const uchar &in[], int ins, uchar &out[], int outl, const int o_s); static __forceinline void SHAKE256(const uchar &in[], int ins, uchar &out[], int outl, const int o_s); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ //--- keccak-f[1600] funcion base // s =arrya de entarad (25) size ya con static void CCryptoHashSHA3::SHA3_KECCAK_F(ulong &s[]) { //--- Constatnes static const int rho[25] = {0, 1, 62, 28, 27, 36, 44, 6, 55, 20, 3, 10, 43, 25, 39, 41, 45, 15, 21, 8, 18, 2, 61, 56, 14}; static const int pi[25] = {0, 10, 20, 5, 15, 16, 1, 11, 21, 6, 7, 17, 2, 12, 22, 23, 8, 18, 3, 13, 14, 24, 9, 19, 4}; static const ulong rc[24] = { 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 }; // Nuestro "valor" en el cual operamos.. /* mapa= 5 filas 5 columnas y cada valor es un lane de 64 bits */ //--- Temp ulong c[5], d[5]; ulong b[25]; //--- Rondas. for(int r = 0; r < 24; r++) { //--- theta /* wiki Calcula la paridad de cada una de las 5 w (320, cuando w = 64 ) columnas de 5 bits y realiza la operación OR exclusiva con dos columnas cercanas siguiendo un patrón regular. Para ser precisos, a [ i ][  j ][ k ] ← a [ i ][  j ][ k ] ⊕ paridad(a[0...4][ j -1][ k ]) ⊕ paridad(a[0...4][ j +1][ k −1] ) */ // Por cada columna /*for(int x = 0; x < 5; x++) c[x] = s[x] ^ s[x + 5] ^ s[x + 10] ^ s[x + 15] ^ s[x + 20]; */ // Denserollado: c[0] = s[0] ^ s[5] ^ s[10] ^ s[15] ^ s[20]; c[1] = s[1] ^ s[6] ^ s[11] ^ s[16] ^ s[21]; c[2] = s[2] ^ s[7] ^ s[12] ^ s[17] ^ s[22]; c[3] = s[3] ^ s[8] ^ s[13] ^ s[18] ^ s[23]; c[4] = s[4] ^ s[9] ^ s[14] ^ s[19] ^ s[24]; // Final //for(int x = 0; x < 5; x++) /*{ const ulong cr = c[(x + 1) % 5]; d[x] = c[(x + 4) % 5] ^ ((cr << 1) | (cr >> 63)); }*/ // Denserollado { const ulong cr = c[1]; d[0] = c[4] ^ ((cr << 1) | (cr >> 63)); } { const ulong cr = c[2]; d[1] = c[0] ^ ((cr << 1) | (cr >> 63)); } { const ulong cr = c[3]; d[2] = c[1] ^ ((cr << 1) | (cr >> 63)); } { const ulong cr = c[4]; d[3] = c[2] ^ ((cr << 1) | (cr >> 63)); } { const ulong cr = c[0]; d[4] = c[3] ^ ((cr << 1) | (cr >> 63)); } // unrrolled s[0] ^= d[0]; s[1] ^= d[1]; s[2] ^= d[2]; s[3] ^= d[3]; s[4] ^= d[4]; s[5] ^= d[0]; s[6] ^= d[1]; s[7] ^= d[2]; s[8] ^= d[3]; s[9] ^= d[4]; s[10] ^= d[0]; s[11] ^= d[1]; s[12] ^= d[2]; s[13] ^= d[3]; s[14] ^= d[4]; s[15] ^= d[0]; s[16] ^= d[1]; s[17] ^= d[2]; s[18] ^= d[3]; s[19] ^= d[4]; s[20] ^= d[0]; s[21] ^= d[1]; s[22] ^= d[2]; s[23] ^= d[3]; s[24] ^= d[4]; //--- RHO+PI for(int i = 0; i < 25; i++) { /* Gire bit a bit cada una de las 25 palabras por un número triangular diferente 0, 1, 3, 6, 10, 15, .... (rho[]) Para ser precisos, a [0][0] no se rota, y para todo 0 ≤ t < 24 , a [ i ][  j ][ k ] ← a [ i ][  j ][ k −( t +1)( t +2)/2] , donde */ const int n = rho[i]; b[pi[i]] = (n == 0) ? s[i] : ((s[i] << n) | (s[i] >> (64 - n))); } //--- CHI fila a fila for(int y = 0; y < 5; y++) { /* Combinación bit a bit a lo largo de las filas, usando x ← x ⊕ (¬ y & z ) . Para ser precisos, a [ i ][  j ][ k ] ← a [ i ][  j ][ k ] ⊕ (¬ a [ i ][  j + 1 ][ k ] &a a [ i ][  j + 2 ][ k ]) . Esta es la única operación no lineal en SHA-3. */ //--- ulong row0 = b[5 * y], row1 = b[1 + 5 * y], row2 = b[2 + 5 * y], row3 = b[3 + 5 * y], row4 = b[4 + 5 * y]; //--- s[5 * y] = row0 ^ ((~row1) & row2); s[1 + 5 * y] = row1 ^ ((~row2) & row3); s[2 + 5 * y] = row2 ^ ((~row3) & row4); s[3 + 5 * y] = row3 ^ ((~row4) & row0); s[4 + 5 * y] = row4 ^ ((~row0) & row1); } //--- iota s[0] ^= rc[r]; } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #define SHA3_CHUNKT_IMP(BYTES, DLIM, P) \ struct SHA3_CHUNKT_BUFFER_##P \ { \ const uchar data[BYTES]; \ }; \ struct SHA3_DLIM_BUFFER_##P \ { \ const uchar data[DLIM]; \ }; //--- SHA3_CHUNKT_IMP(SHA3_256_BLOCK_SIZE, SHA3_DELIM_SHA3, SHA3_256) SHA3_CHUNKT_IMP(SHA3_384_BLOCK_SIZE, SHA3_DELIM_SHA3, SHA3_384) SHA3_CHUNKT_IMP(SHA3_512_BLOCK_SIZE, SHA3_DELIM_SHA3, SHA3_512) SHA3_CHUNKT_IMP(SHA3_SHAKE_128_BLOCK_SIZE, SHA3_DELIM_SHAKE, SHA3_SHAKE_128) SHA3_CHUNKT_IMP(SHA3_SHAKE_256_BLOCK_SIZE, SHA3_DELIM_SHAKE, SHA3_SHAKE_256) //+------------------------------------------------------------------+ //| Esepcific implemtantion | //+------------------------------------------------------------------+ static __forceinline void CCryptoHashSHA3::SHA3_256(const uchar &in[], int ins, uchar &out[], const int o_s) { CCryptoHashSHA3::SHA3_HASH(in, ins, out, SHA3_256_OUT_BSIZE, o_s); } static __forceinline void CCryptoHashSHA3::SHA3_384(const uchar &in[], int ins, uchar &out[], const int o_s) { CCryptoHashSHA3::SHA3_HASH(in, ins, out, SHA3_384_OUT_BSIZE, o_s); } static __forceinline void CCryptoHashSHA3::SHA3_512(const uchar &in[], int ins, uchar &out[], const int o_s) { CCryptoHashSHA3::SHA3_HASH(in, ins, out, SHA3_512_OUT_BSIZE, o_s); } static __forceinline void CCryptoHashSHA3::SHAKE128(const uchar &in[], int ins, uchar &out[], int outl, const int o_s) { CCryptoHashSHA3::SHA3_HASH(in, ins, out, outl, o_s); } static __forceinline void CCryptoHashSHA3::SHAKE256(const uchar &in[], int ins, uchar &out[], int outl, const int o_s) { CCryptoHashSHA3::SHA3_HASH(in, ins, out, outl, o_s); } //--- } //--- #endif // CRYPTOBYLEO_SRC_HASH_SHA3_MQH //+------------------------------------------------------------------+