CryptoByLeo/Src/Hash/SHA3.mqh
Nique_372 6d4e2150d3
2026-08-11 18:27:38 -05:00

414 lines
13 KiB
MQL5
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//+------------------------------------------------------------------+
//| 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)
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
namespace TSN
{
//--- keccak-f[1600] funcion base
// s =arrya de entarad (25) size ya con
static void CCryptoHash::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];
}
}
//---
// chunk_t = 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
static void CCryptoHash::SHA3_HASH(const uchar &in[], int ins, uchar &out[],
int outl, int chunk_t, uchar delim)
{
//--- state inciial
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
};
//--- paso 1 absorcion
int pos = 0;
while(ins - pos >= chunk_t)
{
for(int i = 0; i < chunk_t; i += 8)
{
const int k = pos + i;
s[i >> 3] ^= ((uint64_t)in[k]) | ((uint64_t)in[k + 1] << 8) |
((uint64_t)in[k + 2] << 16) | ((uint64_t)in[k + 3] << 24) |
((uint64_t)in[k + 4] << 32) | ((uint64_t)in[k + 5] << 40) |
((uint64_t)in[k + 6] << 48) | ((uint64_t)in[k + 7] << 56);;
}
//---
// HOT PATH inline aqui mismo
//------- statart of mixing
//--- 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];
}
//-----
//------- end of mixing
pos += chunk_t;
}
// 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)
uchar block[200];
ArrayInitialize(block, 0);
//---
const int rem = ins - pos;
//---
for(int i = 0; i < rem; i++)
block[i] = in[pos + i];
//---
block[rem] = delim;
block[chunk_t - 1] |= 0x80;
//--- Ahora lo que sobra..
for(int i = 0; i < chunk_t; i += 8)
{
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 >> 3] ^= w;
}
SHA3_KECCAK_F(s);
// Pase final exprimimos todo loq eu tenemos..
//---
int ops = 0;
while(ops < outl)
{
//---
int t = outl - ops; // tomado
if(t > chunk_t)
t = chunk_t; // 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[ops + i] = (uchar)(s[i >> 3] >> sh); // escribimos
}
ops += t; // aumentaos lo que ya tenemos
//---
if(ops < outl) // volvemos.. se requier mas de lo normal asi qeu aplicanos denuevo para la nueva salida
SHA3_KECCAK_F(s);
}
}
//+------------------------------------------------------------------+
//| Esepcific implemtantion |
//+------------------------------------------------------------------+
static __forceinline void CCryptoHash::SHA3_256(const uchar &in[], int ins, uchar &out[])
{
SHA3_HASH(in, ins, out, 32, 136, SHA3_DELIM_SHA3);
}
static __forceinline void CCryptoHash::SHA3_512(const uchar &in[], int ins, uchar &out[])
{
SHA3_HASH(in, ins, out, 64, 72, SHA3_DELIM_SHA3);
}
static __forceinline void CCryptoHash::SHAKE128(const uchar &in[], int ins, uchar &out[], int outl)
{
SHA3_HASH(in, ins, out, outl, 168, SHA3_DELIM_SHAKE);
}
static __forceinline void CCryptoHash::SHAKE256(const uchar &in[], int ins, uchar &out[], int outl)
{
SHA3_HASH(in, ins, out, outl, 136, SHA3_DELIM_SHAKE);
}
//---
}
//---
#endif // CRYPTOBYLEO_SRC_HASH_SHA3_MQH
//+------------------------------------------------------------------+