CryptoByLeo/Src/Simetric/ChaCha20/Main.mqh
2026-08-12 13:31:16 -05:00

237 lignes
8,2 Kio
MQL5

//+------------------------------------------------------------------+
//| Main.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_SIMETRIC_CHACHA20_MAIN_MQH
#define CRYPTOBYLEO_SRC_SIMETRIC_CHACHA20_MAIN_MQH
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#include "Def.mqh"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
namespace TSN
{
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CChaCha20
{
public:
uint32_t m_state[CHACHA20_STATE_S];
public:
CChaCha20(void);
~CChaCha20(void) {}
//---
// key = clave de 32 bytes
// iv = nonce aleatorio por cada bloque a cifrar (tamaño de 12 bytes)
// inicia el estado del cifrador
// Nota que no se veriica nada, se asume que el usuario pasa todo correcto
void Init(const uchar& key[], const uchar& iv[], uint32_t counter = 0);
//---
void XProcces(uchar &in[], int ins);
//--- Extra
void ResetCounter(uint32_t counter = 0) { m_state[CHACHA20_STATE_IDX_CNT] = counter; }
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CChaCha20::CChaCha20()
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CChaCha20::Init(const uchar &key[], const uchar &iv[], uint32_t counter = 0)
{
//--- constnes iniciales
m_state[0] = 0x61707865;
m_state[1] = 0x3320646e;
m_state[2] = 0x79622d32;
m_state[3] = 0x6b206574;
//--- los siuientes 8 vamos cargo 4 bytes de la calve en un uint
for(int i = 0; i < 8; i++)
{
const int s = i << 2; // Empiza ahi
m_state[4 + i] = (uint32_t)key[s] | (uint32_t)key[s + 1] << 8 | (uint32_t)key[s + 2] << 16 | (uint32_t)key[s + 3] << 24;
}
//--- contador
m_state[CHACHA20_STATE_IDX_CNT] = counter;
//---- iv
//for(int i = 0; i < 3; i++)
// unrrolled
m_state[13] = (uint32_t)iv[0] | (uint32_t)iv[1] << 8 | (uint32_t)iv[2] << 16 | (uint32_t)iv[3] << 24;
m_state[14] = (uint32_t)iv[4] | (uint32_t)iv[5] << 8 | (uint32_t)iv[6] << 16 | (uint32_t)iv[7] << 24;
m_state[15] = (uint32_t)iv[8] | (uint32_t)iv[9] << 8 | (uint32_t)iv[10] << 16 | (uint32_t)iv[11] << 24;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CChaCha20::XProcces(uchar &in[], int ins)
{
//----
union U32_8
{
uint32_t u32[CHACHA20_KEYSTREAM_SIZE_U32];
uchar u8[CHACHA20_KEYSTREAM_SIZEB];
} keystream;
//---
const int s = ins - CHACHA20_KEYSTREAM_SIZEB;
int pos = 0;
while(pos < s)
{
//--- Algoritmo base para un ks
// Contruiimos el bloque de 16 (keysteam)
// aqwui instaicniasmpo temporales.
uint32_t x0 = m_state[0], x1 = m_state[1], x2 = m_state[2], x3 = m_state[3];
uint32_t x4 = m_state[4], x5 = m_state[5], x6 = m_state[6], x7 = m_state[7];
uint32_t x8 = m_state[8], x9 = m_state[9], x10 = m_state[10], x11 = m_state[11];
uint32_t x12 = m_state[12], x13 = m_state[13], x14 = m_state[14], x15 = m_state[15];
// bueno ahora aplicamos las rnodnas con la funcion Qr
// 10 unrroled rondas para un total de 10 rondas
CHACHA20_DOUBLE_ROUND
CHACHA20_DOUBLE_ROUND
CHACHA20_DOUBLE_ROUND
CHACHA20_DOUBLE_ROUND
CHACHA20_DOUBLE_ROUND
CHACHA20_DOUBLE_ROUND
CHACHA20_DOUBLE_ROUND
CHACHA20_DOUBLE_ROUND
CHACHA20_DOUBLE_ROUND
CHACHA20_DOUBLE_ROUND
// Ahora aplicamos al finall
// unrroled (16) suma + escritura
keystream.u32[0] = x0 + m_state[0];
keystream.u32[1] = x1 + m_state[1];
keystream.u32[2] = x2 + m_state[2];
keystream.u32[3] = x3 + m_state[3];
keystream.u32[4] = x4 + m_state[4];
keystream.u32[5] = x5 + m_state[5];
keystream.u32[6] = x6 + m_state[6];
keystream.u32[7] = x7 + m_state[7];
keystream.u32[8] = x8 + m_state[8];
keystream.u32[9] = x9 + m_state[9];
keystream.u32[10] = x10 + m_state[10];
keystream.u32[11] = x11 + m_state[11];
keystream.u32[12] = x12 + m_state[12];
keystream.u32[13] = x13 + m_state[13];
keystream.u32[14] = x14 + m_state[14];
keystream.u32[15] = x15 + m_state[15];
// Aumentamos el confaodr
m_state[CHACHA20_STATE_IDX_CNT]++;
//--- Next ahora aplicamos... escritura ffinal
for(int i = 0; i < CHACHA20_KEYSTREAM_SIZEB; i++)
{
in[pos + i] ^= keystream.u8[i];
}
//---
pos += CHACHA20_KEYSTREAM_SIZEB;
}
//--- bytes finales
if(pos < ins)
{
//--- Algoritmo base para un ks
// Contruiimos el bloque de 16 (keysteam)
// aqwui instaicniasmpo temporales.
uint32_t x0 = m_state[0], x1 = m_state[1], x2 = m_state[2], x3 = m_state[3];
uint32_t x4 = m_state[4], x5 = m_state[5], x6 = m_state[6], x7 = m_state[7];
uint32_t x8 = m_state[8], x9 = m_state[9], x10 = m_state[10], x11 = m_state[11];
uint32_t x12 = m_state[12], x13 = m_state[13], x14 = m_state[14], x15 = m_state[15];
// bueno ahora aplicamos las rnodnas con la funcion Qr
// 10 unrroled rondas para un total de 10 rondas
CHACHA20_DOUBLE_ROUND
CHACHA20_DOUBLE_ROUND
CHACHA20_DOUBLE_ROUND
CHACHA20_DOUBLE_ROUND
CHACHA20_DOUBLE_ROUND
CHACHA20_DOUBLE_ROUND
CHACHA20_DOUBLE_ROUND
CHACHA20_DOUBLE_ROUND
CHACHA20_DOUBLE_ROUND
CHACHA20_DOUBLE_ROUND
// Ahora aplicamos al finall
// unrroled (16) suma + escritura
keystream.u32[0] = x0 + m_state[0];
keystream.u32[1] = x1 + m_state[1];
keystream.u32[2] = x2 + m_state[2];
keystream.u32[3] = x3 + m_state[3];
keystream.u32[4] = x4 + m_state[4];
keystream.u32[5] = x5 + m_state[5];
keystream.u32[6] = x6 + m_state[6];
keystream.u32[7] = x7 + m_state[7];
keystream.u32[8] = x8 + m_state[8];
keystream.u32[9] = x9 + m_state[9];
keystream.u32[10] = x10 + m_state[10];
keystream.u32[11] = x11 + m_state[11];
keystream.u32[12] = x12 + m_state[12];
keystream.u32[13] = x13 + m_state[13];
keystream.u32[14] = x14 + m_state[14];
keystream.u32[15] = x15 + m_state[15];
// Aumentamos el confaodr
m_state[CHACHA20_STATE_IDX_CNT]++;
//---
const int f = ins - pos;
for(int i = 0; i < f; i++)
{
in[pos + i] ^= keystream.u8[i];
}
}
}
//---
}
//+------------------------------------------------------------------+
#endif // CRYPTOBYLEO_SRC_SIMETRIC_CHACHA20_MAIN_MQH
/*
Por lo que esrtuve enindeod creo que es mas ismple que AEs
primero incializ un estado con una key 4 consatnes y un once (aleatorios)
Luego vas procsenados chunks de 64 bytes.
-
Tomar el estado actuliza lo instiaca luego vas aplicando sumas, xor, rotaciones a ese "x"
temporalce (Copia de state) por 20 rondas...
terminana esas rondas aplicas denueo al estaod (se lo sumas) todos esos temporales
bien emepzlaos, y aumentas el condaor (12)
-
Ahora luego tomas ese aray key stream y aplica un xor en el buffer de salida del cifrado
y luego lo copias al buffer de salia (aqui pasas uint32 a uchar)
//----
Bueno el algoritmo no es tan complejo a decir verdad... mas faicl que AES
Este como tal es el algoritmo puro sin poly.. que se le agrega
*/
//+------------------------------------------------------------------+