; 2013 год
; Шрифт: Lucida Console (10)

// Реализация алгоритма шифрования ГОСТ 28147-89 для MC P1.
// Режим шифрования данных - простая замена.

// Особенности:
// * входной буффер должен быть кратным 8 байтам
// * параметр "blocks_count" указывает количество блоков размером по 8 байт во входном буффере


// void mc_gost_encdec(int direction, unsigned int *key, unsigned int *buf, int blocks_count);



.alias	SP	39	/* Стек. (в алгоритме старшие 4 байта не сохраняются!)*/
.alias	DEC	0	/* Запрошена операция шифрования или расшифровывания */
.alias	AA	1	/* Ai */
.alias	BB	2	/* Bi */
.alias	KI	3	/* Ki */
.alias	BLK	4	/* Текущий номер блока */
.alias	IDX	5	/* Номер раунда */
.alias	SB	32	/* Sblock */


.global mc_gost_encdec

.data

.align 8

Sblock:
    /* Определяем тестовые S-блоки в соответствии с ГОСТ Р 34.11-94 (ГОСТ Р 34.11-94 устарел. С 1 января 2013 года надо использвать ГОСТ Р 34.11-2012)*/
    .quad 0x35F7C1B6E08D29A4
    .quad 0x95701832AFD6C4BE
    .quad 0xB9067CFE243AD185
    .quad 0x352BC64EF9801AD7
    .quad 0x2B30E9A48DF517B6
    .quad 0xEFC95863D1270AB4
    .quad 0xC2867EA095F314BD
    .quad 0xC8B6E3294A750DF1


.bss

.align 8

Keys:
    .long  0

.align 8

BufPtr:
    .long  0


.text

//====================================
    .alias gost_encdec.dec #SP,4	/* operation */
    .alias gost_encdec.key #SP,8	/* pointer keys */
    .alias gost_encdec.buf #SP,12	/* pointer buf */
    .alias gost_encdec.blk #SP,16	/* block count */
    .alias gost_encdec.old_r1 #SP,-8	; Из-за особенностей 'SETx' приходится брать все 8 байт
    .alias gost_encdec.old_r2 #SP,-16
    .alias gost_encdec.old_r3 #SP,-24
    .alias gost_encdec.old_r4 #SP,-32
    .alias gost_encdec.old_r5 #SP,-40
    .alias gost_encdec.old_r6 #SP,-48
    .alias gost_encdec.old_r7 #SP,-56

    .alias gost_encdec.stackb 56	; Количество байт под стек. #BP(#38) не используется.
    .alias gost_encdec.old_r1.newSP #SP,48
    .alias gost_encdec.old_r2.newSP #SP,40
    .alias gost_encdec.old_r3.newSP #SP,32
    .alias gost_encdec.old_r4.newSP #SP,24
    .alias gost_encdec.old_r5.newSP #SP,16
    .alias gost_encdec.old_r6.newSP #SP,8
    .alias gost_encdec.old_r7.newSP #SP

    .alias gost_encdec.RET.newSP #SP, gost_encdec.stackb	; Возврат из функции


mc_gost_encdec:
gost_encdec:

 SP13 :=        getq	#SP	; выделяем наш кадр стека. Часть 1 из 3

 dec :=         rdl	gost_encdec.dec		/* operation */
 key :=         rdl	gost_encdec.key		/* key */
 buf :=         rdl	gost_encdec.buf		/* buf */
 blk :=         rdl	gost_encdec.blk		/* block count */

	; Получение значений регистров
 old1 :=        getq	#DEC
 old2 :=        getq	#AA
 old3 :=        getq	#BB
 old4 :=        getq	#KI
 old5 :=        getq	#BLK
 old6 :=        getq	#IDX
 old7 :=        getq	#SB

 SP23 :=        subl	@SP13, gost_encdec.stackb	; выделяем наш кадр стека. Часть 2 из 3

                setl	#DEC, @dec
                wrl	@key, Keys
                setl	#BLK, @blk
                wrl	@buf, BufPtr

                setl	#SB, Sblock

                setl	#SP, @SP23	; выделяем наш кадр стека. Часть 3 из 3

	; Сохранение старых значений регистров в стеке
                wrq	@old1, gost_encdec.old_r1
                wrq	@old2, gost_encdec.old_r2
                wrq	@old3, gost_encdec.old_r3
                wrq	@old4, gost_encdec.old_r4
                wrq	@old5, gost_encdec.old_r5
                wrq	@old6, gost_encdec.old_r6
                wrq	@old7, gost_encdec.old_r7

                jmp	gost.next_block

complete

//====================================

gost.next_block:

 r1 :=          getl	#BLK
 r2 :=          subl	@r1, 1
                setl	#BLK, @r2

                je	@r1, gost.return
                jne	@r1, gost.fetch_block

complete

//====================================

gost.fetch_block:

 r1 :=          getl	#DEC

 r2 :=          rdl	BufPtr		/* указатель на буффер */
 r3 :=          addl	@r2, 4

 r4 :=          rdl	@r2		/* считывает два первых значения */
 r5 :=          rdl	@r3

                setl	#AA, @r4
                setl	#BB, @r5

                je	@r1, gost_enc.prologue
                jne	@r1, gost_dec.prologue

complete

//====================================

gost_enc.prologue:

                setl	#IDX, 0

                jmp	gost.load_key1_24

complete

//====================================

gost_dec.prologue:

                setl	#IDX, 31

                jmp	gost.load_key25_32

complete

//====================================

gost.load_key1_24:

 kp :=          rdl	Keys
 r1 :=          getl	#IDX

 r2 :=          and	@r1, 7		/* Ограничиваем i пределами [0..7] */
 r3 :=          slll	@r2, 2		/* Смещение до Ki */
 r4 :=          addl	@kp, @r3	/* Ki = kp + i*4 */
 r5 :=          rdl	@r4
                setl	#KI, @r5

                jmp	gost.round

complete

//====================================

gost.load_key25_32:

 kp :=          rdl	Keys
 r1 :=          getl	#IDX

 r2 :=          and	@r1, 7		/* Ограничиваем i пределами [7..0] */
 r3 :=          slll	@r2, 2		/* Смещение до Ki */
 r4 :=          addl	@kp, 7 * 4	/* Пермещаем указатель к последнему элементу */
 r5 :=          subl	@r4, @r3	/* Отсчитываем ключ с конца: Ki = kp - i*4 */
 r6 :=          rdl	@r5
                setl	#KI, @r6

                jmp	gost.round

complete

//====================================

gost.round:

 r1 :=          getl	#KI

	/* Сохраняем в коммутатор 8 значений Sblock */
 s0 :=          rdq	#SB
 s1 :=          rdq	#SB, 8
 s2 :=          rdq	#SB, 16

 axk :=         xor	@r1, #AA	/* Сложение Ai + Ki по mod 2 */

 s3 :=          rdq	#SB, 24
 s4 :=          rdq	#SB, 32
 s5 :=          rdq	#SB, 40
 s6 :=          rdq	#SB, 48
 s7 :=          rdq	#SB, 56

	/* Разбиваем на 4-х битную подпоследовательность */
 r3 :=          slrl	@axk, 4
 r4 :=          slrl	@axk, 8
 r5 :=          slrl	@axk, 12
 r6 :=          slrl	@axk, 16
 r7 :=          slrl	@axk, 20
 r8 :=          slrl	@axk, 24
 r9 :=          slrl	@axk, 28
	/* Получаем индекс для каждой подпоследовательности */
 r10 :=         and	@axk, 0xf
 r11 :=         and	@r3, 0xf
 r12 :=         and	@r4, 0xf
 r13 :=         and	@r5, 0xf
 r14 :=         and	@r6, 0xf
 r15 :=         and	@r7, 0xf
 r16 :=         and	@r8, 0xf
 r17 :=         and	@r9, 0xf
	/* ...растягиваем, чтобы потом сдвигать вправо с кратностью по 4 бита */
 r18 :=         slll	@r10, 2
 r19 :=         slll	@r11, 2
 r20 :=         slll	@r12, 2
 r21 :=         slll	@r13, 2
 r22 :=         slll	@r14, 2
 r23 :=         slll	@r15, 2
 r24 :=         slll	@r16, 2
 r25 :=         slll	@r17, 2
	/* Получаем значение по индексу */
 r26 :=         slrq	@s0, @r18
 r27 :=         slrq	@s1, @r19
 r28 :=         slrq	@s2, @r20
 r29 :=         slrq	@s3, @r21
 r30 :=         slrq	@s4, @r22
 r31 :=         slrq	@s5, @r23
 r32 :=         slrq	@s6, @r24
 r33 :=         slrq	@s7, @r25

 r34 :=         and	@r26, 0xf
 r35 :=         and	@r27, 0xf
 r36 :=         and	@r28, 0xf
 r37 :=         and	@r29, 0xf
 r38 :=         and	@r30, 0xf
 r39 :=         and	@r31, 0xf
 r40 :=         and	@r32, 0xf
 r41 :=         and	@r33, 0xf
	/* Склеиваем подпоследовательности */
 r42 :=         slll	@r35, 4
 r43 :=         slll	@r36, 8
 r44 :=         slll	@r37, 12
 r45 :=         slll	@r38, 16
 r46 :=         slll	@r39, 20
 r47 :=         slll	@r40, 24
 r48 :=         slll	@r41, 28

;мин 3 такта
 r49 :=         or	@r34, @r42
 r50 :=         or	@r43, @r44
 r51 :=         or	@r45, @r46
 r52 :=         or	@r47, @r48
 r53 :=         or	@r49, @r50
 r54 :=         or	@r51, @r52
 r55 :=         or	@r53, @r54

 r61 :=         getl	#DEC

 r56 :=         roll	@r55, 11		/* Циклический сдвиг влево на 11 бит */
 r57 :=         getl	#BB
 r58 :=         xor	@r57, @r56		/* Bi ^ f(Ai,Ki) */
 r59 :=         setl	#BB, #AA		/* Bi+1 = Ai */
 r60 :=         setl	#AA, @r58		/* Ai+1 = Bi ^ f(Ai,Ki) */

 r62 :=         je	@r61, gost_enc.epilogue
 r63 :=         jne	@r61, gost_dec.epilogue

complete

//====================================

gost_enc.epilogue:

 r1 :=          getl	#IDX
 r2 :=          addl	@r1, 1
                setl	#IDX, @r2

 r3 :=          subl	@r2, 24
 r4 :=          subl	@r2, 32

 r5 :=          and	@r3, 0x80000000
                jne	@r5, gost.load_key1_24

 r6 :=          and	@r4, 0x80000000
 r7 :=          xor	@r5, @r6
                jne	@r7, gost.load_key25_32

 r8 :=          or	@r5, @r7

                je	@r8, gost.save_results		; Готово, далее сохраняем и берём следующие значения из буфера

complete

//====================================

gost_dec.epilogue:

 r1 :=          getl	#IDX
 r2 :=          subl	@r1, 1
                setl	#IDX, @r2

                je	@r1, gost.save_results		; Готово, далее сохраняем и берём следующие значения из буфера
                jne	@r1, gost_dec.epilogue.2

complete

gost_dec.epilogue.2:	; Убрали лишнее

 r1 :=          getl	#IDX

 r2 :=          subl	@r1, 24

 r4 :=          and	@r2, 0x80000000
                jne	@r4, gost.load_key1_24

                je	@r4, gost.load_key25_32
complete

/* ; Полный вариант
gost_dec.epilogue.2:

 r1 :=          getl	#IDX

 r2 :=          subl	@r1, 24
 r3 :=          subl	@r1, 32

 r4 :=          and	@r2, 0x80000000
                jne	@r4, gost.load_key1_24

 r5 :=          and	@r3, 0x80000000
 r6 :=          xor	@r5, @r4
                jne	@r6, gost.load_key25_32

                or	@r4, @r6	;Возможно это лишнее надо уточнить (без них на тестовом примере работает норамльно)
                je	gost.round	;Возможно это лишнее надо уточнить (без них на тестовом примере работает норамльно)

complete
*/

//====================================

gost.save_results:

 r1 :=          rdl	BufPtr

 r2 :=          addl	@r1, 4
 newp :=        addl	@r1, 8

 r3 :=          getl	#BB
 r4 :=          getl	#AA

                wrl	@r3, @r1	/* Сохраняем новые значения в буфере */
                wrl	@r4, @r2

                wrl	@newp, BufPtr	/* Сохраняем новый указатель */

                jmp	gost.next_block

complete

//====================================

gost.return:

 SP13 :=        getq	#SP	; убираем наш кадр стека. Часть 1 из 3

	; Восстановление старых значений индексных регистров. Часть 1 из 2
 old7 :=        rdq	gost_encdec.old_r7.newSP
 old6 :=        rdq	gost_encdec.old_r6.newSP
 old5 :=        rdq	gost_encdec.old_r5.newSP
 old4 :=        rdq	gost_encdec.old_r4.newSP
 old3 :=        rdq	gost_encdec.old_r3.newSP
 old2 :=        rdq	gost_encdec.old_r2.newSP
 old1 :=        rdq	gost_encdec.old_r1.newSP

 NP :=          rdl	gost_encdec.RET.newSP	; Следующий параграф. Часть 1 из 2

 SP23 :=        addl	@SP13, gost_encdec.stackb	; убираем наш кадр стека. Часть 2 из 3

	; Восстановление старых значений индексных регистров. Часть 2 из 2
                setq	#SB, @old7
                setq	#IDX, @old6
                setq	#BLK, @old5
                setq	#KI, @old4
                setq	#BB, @old3
                setq	#AA, @old2
                setq	#DEC, @old1

                setl	#SP, @SP23	; убираем наш кадр стека. Часть 3 из 3

                jmp	@NP	; Следующий параграф. Часть 2 из 2

complete

//====================================
