Разоблачение данных веб-сокета / многобайтовый xor

Спецификация websocket определяет демаскирование данных как

j                   = i MOD 4
transformed-octet-i = original-octet-i XOR masking-key-octet-j

где маска имеет длину 4 байта, и на каждый байт следует применять маску.

Есть ли способ сделать это более эффективно, чем просто зациклить байты?

Сервер, на котором выполняется код, можно считать процессором Haswell, ОС - Linux с ядром> 3.2, поэтому SSE и т. Д. Все присутствуют. Кодирование сделано на C, но я могу также сделать asm, если это необходимо.

Я попытался найти решение самостоятельно, но не смог выяснить, была ли соответствующая инструкция в какой-либо из дюжин SSE1-5/AVE/(какое бы расширение не было потеряно из-за многих лет)

Большое спасибо!

Редактировать: после перечитывания спецификации пару раз кажется, что на самом деле это только XOR'ы байтов данных с байтами маски, что я могу сделать 8 байтов за раз до последних нескольких байтов. Вопрос все еще остается открытым, так как я думаю, что, возможно, еще есть способ оптимизировать это с помощью SSE или тому подобного (возможно, обрабатывать хотя бы 16 байтов за раз, позволяя процессу выполнять цикл for? ...)

1 ответ

Решение

Да, вы можете XOR 16 байтов в одной инструкции, используя SSE2, или 32 байта за раз с AVX2 (Haswell и позже).

SSE2:

#include <emmintrin.h>                     // SSE2 instrinsics

__m128i v, v_mask;
uint8_t *buff;                             // buffer - must be 16 byte aligned

for (int i = 0; i < N; i += 16)            // note that N must be multiple of 16
{
    v = _mm_load_si128(&buff[i]);          // load 16 bytes
    v = _mm_xor_si128(v, v_mask);          // XOR with mask
    v = _mm_store_si128(&buff[i], v);      // store 16 masked bytes
}

AVX2:

#include <immintrin.h>                     // AVX2 intrinsics

__m256i w, w_mask;
uint8_t *buff;                             // buffer - must be 16 byte aligned,
                                           // and preferably 32 byte aligned

for (int i = 0; i < N; i += 32)            // note that N must be multiple of 32
{
    w = _mm256_load_si256(&buff[i]);       // load 32 bytes
    w = _mm256_xor_si256(w, w_mask);       // XOR with mask
    w = _mm256_store_si256(&buff[i], w);   // store 32 masked bytes
}
Другие вопросы по тегам