// ESP32 RIPEMD160
// З обмеженням в 1 блок (максимальна довжина вхідних даних 55 байт)
// https://wokwi.com/projects/406993597432064001 (ESP32 RIPEMD-160)
// https://wokwi.com/projects/398636708003334145 (ESP32 SHA-256)
// https://wokwi.com/projects/415477124481441793 (ESP32 SHA-256)
// https://sopkit.github.io/Encoding/ripemd_160.html
// in (3 bytes UTF-8): abc
// out (20 bytes): 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc
// in (32 bytes HEX): 58618FFFE27F39D1F68D8D4EB5D496AB6925D1C0E981A522720495A9720552EF
// out (20 bytes): a65d1a239d4ec666643d350c7bb8fc44d2881128
// Бітовий зсув на n біт
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
// Глобальні RIPEMD регісти
unsigned int H0, H1, H2, H3, H4;
// Ініціалізація вибору 32-бітних слів з буферу даних для 1 потоку
unsigned int R1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13};
// Ініціалізація вибору 32-бітних слів з буферу даних для 2 потоку
unsigned int R2[] = { 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11};
// Ініціалізація масиву для бітового зсуву для 1 потоку
unsigned int S1[] = { 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6};
// Ініціалізація масиву для бітового зсуву для 2 потоку
unsigned int S2[] = { 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11};
// Вибір функції в відповідності до номеру циклу
unsigned int myF(int i, unsigned int x, unsigned int y, unsigned int z) {
if (i < 16) return x ^ y ^ z;
else if (i < 32) return (x & y) | (~x & z);
else if (i < 48) return (x | ~y) ^ z;
else if (i < 64) return (x & z) | (y & ~z);
else if (i < 80) return x ^ (y | ~z);
else return 0;
}
// Вибір константи в відповідності до номеру циклу для 1 потоку
unsigned int K1(int i) {
if (i < 16) return 0x00000000;
else if (i < 32) return 0x5A827999;
else if (i < 48) return 0x6ED9EBA1;
else if (i < 64) return 0x8F1BBCDC;
else if (i < 80) return 0xA953FD4E;
else return 0;
}
// Вибір константи в відповідності до номеру циклу для 2 потоку
unsigned int K2(int i) {
if (i < 16) return 0x50A28BE6;
else if (i < 32) return 0x5C4DD124;
else if (i < 48) return 0x6D703EF3;
else if (i < 64) return 0x7A6D76E9;
else if (i < 80) return 0x00000000;
else return 0;
}
// Інверсія 4 байтів
unsigned int inv(unsigned int value) {
unsigned int res = (value & 0xFF) << 24;
res |= ((value >> 8) & 0xFF) << 16;
res |= ((value >> 16) & 0xFF) << 8;
res |= (value >> 24) & 0xFF;
return res;
}
void RIPEMD160() {
// Буфер вхідних даних (16*4 = 64 байта)
unsigned int X[16] = {0};
// Вхідні дані (UTF-8): abc
X[0] = 0x80636261; // "abc" (80 -> end, c -> 63, b -> 62, a -> 61)
X[14] = 24; // "abc" (len = 3) 3*8 = 24 - довжина вхідних даних
/*
// Вхідні дані (HEX): 58618FFFE27F39D1F68D8D4EB5D496AB6925D1C0E981A522720495A9720552EF
X[0] = 0xFF8F6158;
X[1] = 0xD1397FE2;
X[2] = 0x4E8D8DF6;
X[3] = 0xAB96D4B5;
X[4] = 0xC0D12569;
X[5] = 0x22A581E9;
X[6] = 0xA9950472;
X[7] = 0xEF520572;
X[8] = 0x00000080; // 0x80 - end
X[14] = 256; // (len = 32) 32*8 = 256 - довжина вхідних даних 256 біт
*/
// Тестовий вивід вхідних даних
//for (int i = 0; i < 16; i++) {printf("%d - %d\n", i, X[i]);}
// Ініціалізація RIPEMD регістрів для двох потоків
H0 = 0x67452301;
H1 = 0xEFCDAB89;
H2 = 0x98BADCFE;
H3 = 0x10325476;
H4 = 0xC3D2E1F0;
// RIPEMD проміжні регістри
unsigned int A1, B1, C1, D1, E1, A2, B2, C2, D2, E2, T;
A1 = H0, B1 = H1, C1 = H2, D1 = H3, E1 = H4;
A2 = H0, B2 = H1, C2 = H2, D2 = H3, E2 = H4;
// 80 циклів
for (int i = 0; i < 80; i++) {
// Потік 1
T = ROTATE_LEFT((A1 + myF(i, B1, C1, D1) + X[R1[i]] + K1(i)), S1[i]) + E1;
A1 = E1, E1 = D1, D1 = ROTATE_LEFT(C1, 10), C1 = B1, B1 = T;
// Потік 2
T = ROTATE_LEFT((A2 + myF(79 - i, B2, C2, D2) + X[R2[i]] + K2(i)), S2[i]) + E2;
A2 = E2, E2 = D2, D2 = ROTATE_LEFT(C2, 10), C2 = B2, B2 = T;
}
// Кінцеві розрахунки
T = H1 + C1 + D2;
H1 = H2 + D1 + E2;
H2 = H3 + E1 + A2;
H3 = H4 + A1 + B2;
H4 = H0 + B1 + C2;
H0 = T;
}
void setup() {
Serial.begin(115200);
uint64_t time = micros();
RIPEMD160();
time = micros() - time;
Serial.println("abc");
Serial.println(inv(H0), HEX); // 8EB208F7
Serial.println(inv(H1), HEX); // E05D987A
Serial.println(inv(H2), HEX); // 9B044A8E
Serial.println(inv(H3), HEX); // 98C6B087
Serial.println(inv(H4), HEX); // F15A0BFC
Serial.printf("Time: %llu us\n\n", time); // 1366 us
}
void loop() {
delay(10);
}