Vlákno názorů k článku Rozšíření instrukční sady AVX-512 na platformě x86–64 (dokončení) od Kevil - Pomocí instrukcí AVX2 jsem naprogramoval funkci pro šifrování...

  • Článek je starý, nové názory již nelze přidávat.
  • 5. 12. 2022 1:00

    Kevil

    Pomocí instrukcí AVX2 jsem naprogramoval funkci pro šifrování HMAC, SHA1. Funkci SHA1 mi funguje pro vstupní text "Ahoj1234", který je menší než 64 bytů. Po doplnění funkce HMAC mi ale výpočet s testovacími daty nefunguje správně a nemohu přijít na to kde mám chybu.

    Testovací data pro HMAC, SHA1 jsou:
    key = "Jefe"
    message = "what do ya want for nothing?"
    viz Test Cases for HMAC-MD5 and HMAC-SHA-1

    Výsledek by měl být:
    effcdf6ae5eb2fa2d274­16d5f184df9c259a7c79

    spočítá ale:
    974020ac606d3­8554f91a4786d23a­ec3cf4d77de

    viz HMAC generator zde
    SHA1 generator tady

    Vlastní kód (Visual Studio 2022, C++ a AVX2)

    32 bitová data ukládá Visual Studio 2022 ve tvaru little endian tj. string "Ahoj1234" je uložen jako "johA" a "4321" (lsb na první místo v paměti).
    Specifikace HMAC požaduje uložení počtu bitů šifrované zprávy jako 64bitové big-endian číslo, pracuji s ním ale jako s 32 bitovým little-endian číslem (posledních 32 bitů v druhé AVX2 části 128 bitů a vyzkoušel jsem, že pro test SHA1 "Ahoj1234" to funguje správně.

    #include <iostream>
    
    #include <immintrin.h>
    #include <chrono>
    #include <stdint.h>
    #include <stdio.h>
    #include <intrin.h>     // Byte swap, unsigned long _byteswap_ulong(unsigned long value);
    
    #ifndef __cplusplus
    #include <stdalign.h>   // C11 defines _Alignas().  This header defines alignas()
    #endif
    
    
    using namespace std;
    using namespace std::chrono;
    
    uint32_t result;
    
    __m256i sha1res;  // výsledek SHA1
    __m256i key;
    __m256i indata[4];  //2x 512 bitů pro vstup HMAC
    
    // HMAC block size block size of the SHA1 hash function is 64 bytes, output size pro SHA1 is 20 bytes
    // https://en.m.wikipedia.org/wiki/HMAC
    
    // SHA1
    // https://en.wikipedia.org/wiki/SHA-1
    
    
    void p256_hex_u32(__m256i in) {
        alignas(32) uint32_t v[8];
        _mm256_maskstore_epi32((int*)v, _mm256_setr_epi32(-1, -1, -1, -1, -1, 0, 0, 0), in);
        printf("v8_u32: %x %x %x %x %x\n", v[0], v[1], v[2], v[3], v[4]);
    }
    
    inline uint32_t rotl32_30(uint32_t value) {
        return value << 30 | value >> 2;
    }
    
    inline uint32_t rotl32_5(uint32_t value) {
        return value << 5 | value >> 27;
    }
    
    inline uint32_t rotl32_1(uint32_t value) {
        return value << 1 | value >> 31;
    }
    
    uint32_t rotl32(uint32_t value, unsigned int count) {
        return value << count | value >> (32 - count);
    }
    
    void SHA1(__m256i* indata) {
        uint32_t pole[80];
        __m256i data;
    
        uint32_t h0 = 0x67452301, a = h0;
        uint32_t h1 = 0xEFCDAB89, b = h1;
        uint32_t h2 = 0x98BADCFE, c = h2;
        uint32_t h3 = 0x10325476, d = h3;
        uint32_t h4 = 0xC3D2E1F0, e = h4;
    
        for (int k = 0; k < 2; k++) {
    
            data = _mm256_load_si256(indata + k * 2);
            _mm256_store_si256((__m256i*)pole, data);
            data = _mm256_load_si256(indata + k * 2 + 1);
            _mm256_store_si256((__m256i*)pole + 1, data );
    
            uint32_t temp;
    
            for (int i = 0; i < 80; i++) {
                if (i > 15) {
                    pole[i] = rotl32_1((pole[i - 3] ^ pole[i - 8] ^ pole[i - 14] ^ pole[i - 16]));
                }
                temp = rotl32_5(a) + e + pole[i];
                if (i < 20) {
                    temp += ((b & c) | ((~b) & d)) + 0x5A827999;
                }
                else if (i < 40) {
                    temp += (b ^ c ^ d) + 0x6ED9EBA1;
                }
                else if (i < 60) {
                    temp += ((b & c) | (b & d) | (c & d)) + 0x8F1BBCDC;
                }
                else {
                    temp += (b ^ c ^ d) + 0xCA62C1D6;
                }
    
                e = d;
                d = c;
                c = rotl32_30(b);
                b = a;
                a = temp;
            }
    
            h0 += a;
            h1 += b;
            h2 += c;
            h3 += d;
            h4 += e;
        }
    
        sha1res = _mm256_setr_epi32(h0, h1, h2, h3, h4, 0, 0, 0);
    }
    
    int main() {
    
        __m256i tmp;
    
        auto start = high_resolution_clock::now();
    
        //Pro test funkce SHA1 lze odkomentovat (a komentovat přiřazení pro Jefe..., nutno také změnit parametr pro načítání k, místo k < 2 na k < 1 a dát stopku za sha1res = ...
        //sha1res = 8162b79671480fc441e2d54ee85dea77f43b5bc2
        //viz odkaz na generátor SHA1 v úvodu
        //key = _mm256_setr_epi32(0x41686f6a, 0x31323334, 0x80000000, 0, 0, 0, 0, 0); // "Ahoj1234"
        //indata[0] = key;
        //indata[1] = _mm256_setr_epi32(0, 0, 0, 0, 0, 0, 0, 0x40);
    
        //key = _mm256_setr_epi32(_byteswap_ulong(0x4A656665), 0, 0, 0, 0, 0, 0, 0); // Jefe
        key = _mm256_setr_epi32(0x4A656665, 0, 0, 0, 0, 0, 0, 0); // Jefe
        indata[0] = _mm256_xor_si256(key, _mm256_set1_epi8(0x36));
        indata[1] = _mm256_set1_epi8(0x36);   // 0 XOR 0x36 = 0x36
    
        //tmp = _mm256_setr_epi32(_byteswap_ulong(0x77686174), _byteswap_ulong(0x20646F20), _byteswap_ulong(0x79612077), _byteswap_ulong(0x616E7420), _byteswap_ulong(0x666F7220), _byteswap_ulong(0x6E6F7468), _byteswap_ulong(0x696E673F), 0); // "what do ya want for nothing?" 28 znaků
        tmp = _mm256_setr_epi32(0x77686174, 0x20646F20, 0x79612077, 0x616E7420, 0x666F7220, 0x6E6F7468, 0x696E673F, 0); // "what do ya want for nothing?" 28 znaků
        indata[2] = _mm256_or_si256(tmp, _mm256_setr_epi32(0, 0, 0, 0, 0, 0, 0, 0x80000000));
        indata[3] = _mm256_setr_epi32(0, 0, 0, 0, 0, 0, 0, 736);  //počet bitů pri ipad hashování = (64 + 28) * 8
    
        SHA1(indata);
    
        indata[0] = _mm256_xor_si256(key, _mm256_set1_epi8(0x5c));
        indata[1] = _mm256_set1_epi8(0x5c);   // 0 XOR 0x5c = 0x5c
        indata[2] = _mm256_or_si256(sha1res, _mm256_setr_epi32(0, 0, 0, 0, 0, 0x80000000, 0, 0));
        indata[3] = _mm256_setr_epi32(0, 0, 0, 0, 0, 0, 0, 672);  //počet bitů pro opad hashování = (64 + 20) * 8
    
        SHA1(indata);
    
        auto stop = high_resolution_clock::now();
        auto duration = duration_cast<microseconds>(stop - start);
        printf("Time  = %lli (us DEC)\n", duration.count());
        p256_hex_u32(sha1res);
    
     }
  • 6. 12. 2022 16:02

    cc

    Ve fóru ti nikdo nepomohl tak to spamuješ sem?