помогите пожалуйста найти оптимизированное решение. НАшел под MMX Код (Text): // SHA-1 MMX implementation, (C) 2005 Simon Marechal // This code computes two SHA-1 digests at the same time. It // doesn't take care of padding (0x80 and size << 3), so make // sure the last input block is properly padded. Both 64-byte // input blocks must be (four bytes) interleaved. #ifdef __i386__ .globl shammx_init .globl shammx_ends; .globl shammx_data; .globl _shammx_init; .globl _shammx_ends; .globl _shammx_data; .data .align(16) const_init_a: .long 0x67452301 .long 0x67452301 const_init_b: .long 0xEFCDAB89 .long 0xEFCDAB89 const_init_c: .long 0x98BADCFE .long 0x98BADCFE const_init_d: .long 0x10325476 .long 0x10325476 const_init_e: .long 0xC3D2E1F0 .long 0xC3D2E1F0 const_stage0: .long 0x5A827999 .long 0x5A827999 const_stage1: .long 0x6ED9EBA1 .long 0x6ED9EBA1 const_stage2: .long 0x8F1BBCDC .long 0x8F1BBCDC const_stage3: .long 0xCA62C1D6 .long 0xCA62C1D6 const_ff00: .long 0xFF00FF00 .long 0xFF00FF00 const_00ff: .long 0x00FF00FF .long 0x00FF00FF #define ctxa %mm0 #define ctxb %mm1 #define ctxc %mm2 #define ctxd %mm3 #define ctxe %mm4 #define tmp1 %mm5 #define tmp2 %mm6 #define tmp3 %mm7 #define tmp4 ctxa #define tmp5 ctxb #define F0(x,y,z) \ movq x, tmp2; \ movq x, tmp1; \ pand y, tmp2; \ pandn z, tmp1; \ por tmp2, tmp1; #define F1(x,y,z) \ movq z, tmp1; \ pxor y, tmp1; \ pxor x, tmp1 #define F2(x,y,z) \ movq x, tmp1; \ movq x, tmp2; \ pand y, tmp1; \ por y, tmp2; \ pand z, tmp2; \ por tmp2, tmp1; #define subRoundX(a, b, c, d, e, f, k, data) \ f(b,c,d); \ movq a, tmp2; \ movq a, tmp3; \ paddd tmp1, e; \ pslld $5, tmp2; \ psrld $27, tmp3; \ por tmp3, tmp2; \ paddd tmp2, e; \ movq b, tmp2; \ pslld $30, b; \ paddd k, e; \ psrld $2, tmp2; \ por tmp2, b; \ movq (data*8)(%edx), tmp1; \ movq tmp1, tmp2; \ pand const_ff00, tmp1; \ pand const_00ff, tmp2; \ psrld $8, tmp1; \ pslld $8, tmp2; \ por tmp2, tmp1; \ movq tmp1, tmp2; \ psrld $16, tmp1; \ pslld $16, tmp2; \ por tmp2, tmp1; \ movq tmp1, (data*8)(%ecx); \ paddd tmp1, e; #define subRoundY(a, b, c, d, e, f, k, data) \ movq ((data- 3)*8)(%ecx), tmp1; \ pxor ((data- 8)*8)(%ecx), tmp1; \ pxor ((data-14)*8)(%ecx), tmp1; \ pxor ((data-16)*8)(%ecx), tmp1; \ movq tmp1, tmp2; \ pslld $1, tmp1; \ psrld $31, tmp2; \ por tmp2, tmp1; \ movq tmp1, (data*8)(%ecx); \ paddd tmp1, e; \ f(b,c,d); \ movq a, tmp2; \ movq a, tmp3; \ paddd tmp1, e; \ pslld $5, tmp2; \ psrld $27, tmp3; \ por tmp3, tmp2; \ paddd tmp2, e; \ movq b, tmp2; \ pslld $30, b; \ paddd k, e; \ psrld $2, tmp2; \ por tmp2, b; .text // arg 1 (eax): context (40 bytes) shammx_init: _shammx_init: movq const_init_a, ctxa movq const_init_b, ctxb movq const_init_c, ctxc movq const_init_d, ctxd movq const_init_e, ctxe movq ctxa, 0(%eax) movq ctxb, 8(%eax) movq ctxc, 16(%eax) movq ctxd, 24(%eax) movq ctxe, 32(%eax) ret // arg 1 (eax): context (40 bytes) // arg 2 (edx): digests (40 bytes) shammx_ends: _shammx_ends: movq 0(%eax), ctxa movq 8(%eax), ctxb movq 16(%eax), ctxc movq 24(%eax), ctxd movq 32(%eax), ctxe movq const_ff00, tmp3 movq ctxa, tmp1 movq ctxb, tmp2 pand tmp3, ctxa pand tmp3, ctxb movq const_00ff, tmp3 pand tmp3, tmp1 pand tmp3, tmp2 psrld $8, ctxa psrld $8, ctxb pslld $8, tmp1 pslld $8, tmp2 por tmp1, ctxa por tmp2, ctxb movq ctxa, tmp1 movq ctxb, tmp2 psrld $16, ctxa psrld $16, ctxb pslld $16, tmp1 pslld $16, tmp2 por tmp1, ctxa por tmp2, ctxb movq ctxa, 0(%edx) movq ctxb, 8(%edx) movq const_ff00, tmp5 movq ctxc, tmp1 movq ctxd, tmp2 movq ctxe, tmp3 pand tmp5, ctxc pand tmp5, ctxd pand tmp5, ctxe movq const_00ff, tmp5 pand tmp5, tmp1 pand tmp5, tmp2 pand tmp5, tmp3 psrld $8, ctxc psrld $8, ctxd psrld $8, ctxe pslld $8, tmp1 pslld $8, tmp2 pslld $8, tmp3 por tmp1, ctxc por tmp2, ctxd por tmp3, ctxe movq ctxc, tmp1 movq ctxd, tmp2 movq ctxe, tmp3 psrld $16, ctxc psrld $16, ctxd psrld $16, ctxe pslld $16, tmp1 pslld $16, tmp2 pslld $16, tmp3 por tmp1, ctxc por tmp2, ctxd por tmp3, ctxe movq ctxc, 16(%edx) movq ctxd, 24(%edx) movq ctxe, 32(%edx) ret // arg 1 (eax): context (40 bytes) // arg 2 (edx): input data (128 bytes) // arg 3 (ecx): workspace (640 bytes) shammx_data: _shammx_data: movq 0(%eax), ctxa movq 8(%eax), ctxb movq 16(%eax), ctxc movq 24(%eax), ctxd movq 32(%eax), ctxe round0: prefetchnta (%edx) subRoundX( ctxa, ctxb, ctxc, ctxd, ctxe, F0, const_stage0, 0 ); subRoundX( ctxe, ctxa, ctxb, ctxc, ctxd, F0, const_stage0, 1 ); subRoundX( ctxd, ctxe, ctxa, ctxb, ctxc, F0, const_stage0, 2 ); subRoundX( ctxc, ctxd, ctxe, ctxa, ctxb, F0, const_stage0, 3 ); subRoundX( ctxb, ctxc, ctxd, ctxe, ctxa, F0, const_stage0, 4 ); subRoundX( ctxa, ctxb, ctxc, ctxd, ctxe, F0, const_stage0, 5 ); subRoundX( ctxe, ctxa, ctxb, ctxc, ctxd, F0, const_stage0, 6 ); subRoundX( ctxd, ctxe, ctxa, ctxb, ctxc, F0, const_stage0, 7 ); subRoundX( ctxc, ctxd, ctxe, ctxa, ctxb, F0, const_stage0, 8 ); subRoundX( ctxb, ctxc, ctxd, ctxe, ctxa, F0, const_stage0, 9 ); subRoundX( ctxa, ctxb, ctxc, ctxd, ctxe, F0, const_stage0, 10 ); subRoundX( ctxe, ctxa, ctxb, ctxc, ctxd, F0, const_stage0, 11 ); subRoundX( ctxd, ctxe, ctxa, ctxb, ctxc, F0, const_stage0, 12 ); subRoundX( ctxc, ctxd, ctxe, ctxa, ctxb, F0, const_stage0, 13 ); subRoundX( ctxb, ctxc, ctxd, ctxe, ctxa, F0, const_stage0, 14 ); subRoundX( ctxa, ctxb, ctxc, ctxd, ctxe, F0, const_stage0, 15 ); subRoundY( ctxe, ctxa, ctxb, ctxc, ctxd, F0, const_stage0, 16 ); subRoundY( ctxd, ctxe, ctxa, ctxb, ctxc, F0, const_stage0, 17 ); subRoundY( ctxc, ctxd, ctxe, ctxa, ctxb, F0, const_stage0, 18 ); subRoundY( ctxb, ctxc, ctxd, ctxe, ctxa, F0, const_stage0, 19 ); round1: subRoundY( ctxa, ctxb, ctxc, ctxd, ctxe, F1, const_stage1, 20 ); subRoundY( ctxe, ctxa, ctxb, ctxc, ctxd, F1, const_stage1, 21 ); subRoundY( ctxd, ctxe, ctxa, ctxb, ctxc, F1, const_stage1, 22 ); subRoundY( ctxc, ctxd, ctxe, ctxa, ctxb, F1, const_stage1, 23 ); subRoundY( ctxb, ctxc, ctxd, ctxe, ctxa, F1, const_stage1, 24 ); subRoundY( ctxa, ctxb, ctxc, ctxd, ctxe, F1, const_stage1, 25 ); subRoundY( ctxe, ctxa, ctxb, ctxc, ctxd, F1, const_stage1, 26 ); subRoundY( ctxd, ctxe, ctxa, ctxb, ctxc, F1, const_stage1, 27 ); subRoundY( ctxc, ctxd, ctxe, ctxa, ctxb, F1, const_stage1, 28 ); subRoundY( ctxb, ctxc, ctxd, ctxe, ctxa, F1, const_stage1, 29 ); subRoundY( ctxa, ctxb, ctxc, ctxd, ctxe, F1, const_stage1, 30 ); subRoundY( ctxe, ctxa, ctxb, ctxc, ctxd, F1, const_stage1, 31 ); subRoundY( ctxd, ctxe, ctxa, ctxb, ctxc, F1, const_stage1, 32 ); subRoundY( ctxc, ctxd, ctxe, ctxa, ctxb, F1, const_stage1, 33 ); subRoundY( ctxb, ctxc, ctxd, ctxe, ctxa, F1, const_stage1, 34 ); subRoundY( ctxa, ctxb, ctxc, ctxd, ctxe, F1, const_stage1, 35 ); subRoundY( ctxe, ctxa, ctxb, ctxc, ctxd, F1, const_stage1, 36 ); subRoundY( ctxd, ctxe, ctxa, ctxb, ctxc, F1, const_stage1, 37 ); subRoundY( ctxc, ctxd, ctxe, ctxa, ctxb, F1, const_stage1, 38 ); subRoundY( ctxb, ctxc, ctxd, ctxe, ctxa, F1, const_stage1, 39 ); round2: subRoundY( ctxa, ctxb, ctxc, ctxd, ctxe, F2, const_stage2, 40 ); subRoundY( ctxe, ctxa, ctxb, ctxc, ctxd, F2, const_stage2, 41 ); subRoundY( ctxd, ctxe, ctxa, ctxb, ctxc, F2, const_stage2, 42 ); subRoundY( ctxc, ctxd, ctxe, ctxa, ctxb, F2, const_stage2, 43 ); subRoundY( ctxb, ctxc, ctxd, ctxe, ctxa, F2, const_stage2, 44 ); subRoundY( ctxa, ctxb, ctxc, ctxd, ctxe, F2, const_stage2, 45 ); subRoundY( ctxe, ctxa, ctxb, ctxc, ctxd, F2, const_stage2, 46 ); subRoundY( ctxd, ctxe, ctxa, ctxb, ctxc, F2, const_stage2, 47 ); subRoundY( ctxc, ctxd, ctxe, ctxa, ctxb, F2, const_stage2, 48 ); subRoundY( ctxb, ctxc, ctxd, ctxe, ctxa, F2, const_stage2, 49 ); subRoundY( ctxa, ctxb, ctxc, ctxd, ctxe, F2, const_stage2, 50 ); subRoundY( ctxe, ctxa, ctxb, ctxc, ctxd, F2, const_stage2, 51 ); subRoundY( ctxd, ctxe, ctxa, ctxb, ctxc, F2, const_stage2, 52 ); subRoundY( ctxc, ctxd, ctxe, ctxa, ctxb, F2, const_stage2, 53 ); subRoundY( ctxb, ctxc, ctxd, ctxe, ctxa, F2, const_stage2, 54 ); subRoundY( ctxa, ctxb, ctxc, ctxd, ctxe, F2, const_stage2, 55 ); subRoundY( ctxe, ctxa, ctxb, ctxc, ctxd, F2, const_stage2, 56 ); subRoundY( ctxd, ctxe, ctxa, ctxb, ctxc, F2, const_stage2, 57 ); subRoundY( ctxc, ctxd, ctxe, ctxa, ctxb, F2, const_stage2, 58 ); subRoundY( ctxb, ctxc, ctxd, ctxe, ctxa, F2, const_stage2, 59 ); round3: subRoundY( ctxa, ctxb, ctxc, ctxd, ctxe, F1, const_stage3, 60 ); subRoundY( ctxe, ctxa, ctxb, ctxc, ctxd, F1, const_stage3, 61 ); subRoundY( ctxd, ctxe, ctxa, ctxb, ctxc, F1, const_stage3, 62 ); subRoundY( ctxc, ctxd, ctxe, ctxa, ctxb, F1, const_stage3, 63 ); subRoundY( ctxb, ctxc, ctxd, ctxe, ctxa, F1, const_stage3, 64 ); subRoundY( ctxa, ctxb, ctxc, ctxd, ctxe, F1, const_stage3, 65 ); subRoundY( ctxe, ctxa, ctxb, ctxc, ctxd, F1, const_stage3, 66 ); subRoundY( ctxd, ctxe, ctxa, ctxb, ctxc, F1, const_stage3, 67 ); subRoundY( ctxc, ctxd, ctxe, ctxa, ctxb, F1, const_stage3, 68 ); subRoundY( ctxb, ctxc, ctxd, ctxe, ctxa, F1, const_stage3, 69 ); subRoundY( ctxa, ctxb, ctxc, ctxd, ctxe, F1, const_stage3, 70 ); subRoundY( ctxe, ctxa, ctxb, ctxc, ctxd, F1, const_stage3, 71 ); subRoundY( ctxd, ctxe, ctxa, ctxb, ctxc, F1, const_stage3, 72 ); subRoundY( ctxc, ctxd, ctxe, ctxa, ctxb, F1, const_stage3, 73 ); subRoundY( ctxb, ctxc, ctxd, ctxe, ctxa, F1, const_stage3, 74 ); subRoundY( ctxa, ctxb, ctxc, ctxd, ctxe, F1, const_stage3, 75 ); subRoundY( ctxe, ctxa, ctxb, ctxc, ctxd, F1, const_stage3, 76 ); subRoundY( ctxd, ctxe, ctxa, ctxb, ctxc, F1, const_stage3, 77 ); subRoundY( ctxc, ctxd, ctxe, ctxa, ctxb, F1, const_stage3, 78 ); subRoundY( ctxb, ctxc, ctxd, ctxe, ctxa, F1, const_stage3, 79 ); paddd 0(%eax), ctxa paddd 8(%eax), ctxb paddd 16(%eax), ctxc paddd 24(%eax), ctxd paddd 32(%eax), ctxe movq ctxa, 0(%eax) movq ctxb, 8(%eax) movq ctxc, 16(%eax) movq ctxd, 24(%eax) movq ctxe, 32(%eax) ret #endif выигрыш - 2 порядка, но что-то я такого синтаксиса не знаю. Можно ли его переписать как под Intel? P.S. Хочу использовать как asm вставку для VC
синтаксис AT&T, местами операнды меняем, добавляем скобочки где нужно и юзаем ps. и где-то я уже видел приведенный в человеческий вид исходник
Не верю. 2 раза — может быть (да и то вряд ли). yasm понимает AT&T'шный синтаксис, но сначала файлик нужно будет прогнать через сишный препроцессор. Также в сети можно найти конверторы из этого синтаксиса в нормальный NASMовский или MASMовский.
нашел время и помучал это чудище, тупо скомпилил gcc, рипнул идой, компильнул masm'ом и собрал либу, т.е. код даже не трогал руками, только вот хэши оно выдает неправильные или что-то я не так понял, если кто-нибудь ещё глянет будет замечательно в аттаче проект msvs80 + sha1 mmx + sha1 x86 [пишет результат через MessageBox] http://slil.ru/25413113
"It doesn't take care of padding (0x80 and size << 3), so make sure the last input block is properly padded."
Это отнюдь не properly. Ассемблерный код shammx_data обрабатывает блоки данных размером 64 байта. Так же делает и функция sha_transform(), которая вызывается из sha_update() (через sha_block()) и из sha_final(). Создание properly padded-блока занимает собственно почти всю функцию sha_final(). После хешируемых даных помещается байт со значением 0x80, далее блок дополняется нулями, кроме последних 8 байт, в которые записывается число хешированных бит как 64-битовое значение. Таким образом, Код (Text): sha_init(&sctx); sha_update(&sctx,(mutils_word8 *)szVector,128); sha_final(&sctx); приведет к трем вызовам sha_transform(). В первом и втором обработаются два 64-байтовых блока с символами '0', а в третьем - padding. Стало быть и вызовов shammx_data должно быть три. И что-то мне подсказывает, что shammx_data вычисляет два хеша параллельно, а не хеш от двух последовательных блоков. Просто sha_transform(), насколько мне известно, устроена так, что до окончания обработки i-ого блока не получится начать обрабатывать i+1-ый... И, кстати, стоит проверить, что там с Byte Ordering - вроде традиционная реализация MD5 байты в каждом DWORD-е переворачивает, про SHA не уверен, но наверняка в нем то же самое. Фраза "Both 64-byte input blocks must be (four bytes) interleaved" как раз про это. Для блоков, заполненных одинаковыми байтами, это не влияет на результат, а padding скорее всего придется переворачивать.
мды, а я так надеялся... так надеялся, что все таки properly фактически в этом mmx коде не хватает процедуры sha_transform()