Here's an asm optimized implementation you can play with ...
Code: Select all
;==================================
; Module: Rabbit
; Author: Wilbert
; Date: Nov 12, 2020
;==================================
DeclareModule Rabbit
;-RabbitCtx structure
Structure RabbitCtx
X.l[8] ; State
C.l[8] ; Counters
Carry.l ; Carry for counters
EndStructure
;-Exported functions
Declare SetKeyAndIV(*Ctx.RabbitCtx, *Key, *IV)
Declare ProcessBytes(*Ctx.RabbitCtx, *Input, *Output, Size)
Declare CryptMemory(*Input, *Output, Size, *Key, *InitVector = #Null)
EndDeclareModule
Module Rabbit
DisableDebugger
EnableExplicit
EnableASM
;- Private structures
Structure Mem64Byte
l.l[16]
EndStructure
;- Private macros
CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
Macro rbx : ebx : EndMacro ; replace rbx with ebx on x86
Macro rcx : ecx : EndMacro ; replace rcx with ecx on x86
Macro rdx : edx : EndMacro ; replace rdx with edx on x86
Macro rsi : esi : EndMacro ; replace rsi with esi on x86
Macro rdi : edi : EndMacro ; replace rdi with edi on x86
Macro rsp : esp : EndMacro ; replace rsp with esp on x86
CompilerEndIf
Macro M_AddWithCarry(n, v)
mov eax, [rcx + n*4 + 32] ; get c[n]
adc eax, v ; add with carry v
mov [rcx + n*4 + 32], eax ; set c[n]
EndMacro
Macro M_GFunction(n)
mov eax, [rcx + n*4] ; get x[n]
add eax, [rcx + n*4 + 32] ; add c[n]
mul eax ; eax*eax, result edx:eax
XOr eax, edx ; xor lower and upper result bits
mov [rsp + n*4], eax ; set g[n]
EndMacro
Macro M_NewStateValue(n, n1, r1, n2, r2)
mov eax, [rsp + n1*4] ; get g[n1]
mov edx, [rsp + n2*4] ; get g[n2]
rol eax, r1 ; rol n1, r1
CompilerIf r2
rol edx, r2 ; rol n2, r2
CompilerEndIf
add eax, edx ; add together
add eax, [rsp + n*4] ; add g[n]
mov [rcx + n*4], eax ; set x[n]
EndMacro
Macro M_SetStateAndCounter(k, n1, n2)
CompilerIf k = 14 ; get key bits
mov eax, [rdx]
shl eax, 16
Or ax, [rdx + 14]
CompilerElse
mov eax, [rdx + k]
CompilerEndIf
mov [rcx + n1*4], eax ; set x[n1]
rol eax, 16
mov [rcx + n2*4 + 32], eax ; set c[n2]
EndMacro
Macro M_ModifyCounter(n1, n2)
mov eax, [rcx + n2*4] ; get x[n2]
XOr [rcx + n1*4 + 32], eax ; c[n1] ! x[n2]
EndMacro
Macro M_XorStreamBytes(n1, n2, n3, n4, f=0)
mov eax, [rcx + n3*4] ; get x[n3]
mov edx, [rcx + n4*4] ; get x[n4]
shrd eax, edx, 16 ; (x[n3] >> 16) | (x[n4] << 16)
XOr eax, [rcx + n2*4] ; xor x[n2]
CompilerIf f=0
XOr eax, [rsi + n1*4]
mov [rdi + n1*4], eax
CompilerElse
mov [rsp + n1*4], eax
CompilerEndIf
EndMacro
;- Public functions
Procedure SetKeyAndIV(*Ctx.RabbitCtx, *Key, *IV)
Protected M.Mem64Byte
; *Key : Pointer to 128 bit key
; *IV : Pointer to 64 bit initialization vector
mov rcx, [p.p_Ctx]
mov rdx, [p.p_Key]
; Generate initial state and counter values
M_SetStateAndCounter( 0, 0, 4)
M_SetStateAndCounter( 2, 5, 1)
M_SetStateAndCounter( 4, 2, 6)
M_SetStateAndCounter( 6, 7, 3)
M_SetStateAndCounter( 8, 4, 0)
M_SetStateAndCounter(10, 1, 5)
M_SetStateAndCounter(12, 6, 2)
M_SetStateAndCounter(14, 3, 7)
; Reset carry flag
mov dword [rcx + 64], 0
; Process 64 bytes
ProcessBytes(*Ctx, @M, @M, 64)
; Modify counters
mov rcx, [p.p_Ctx]
M_ModifyCounter(0, 4)
M_ModifyCounter(1, 5)
M_ModifyCounter(2, 6)
M_ModifyCounter(3, 7)
M_ModifyCounter(4, 0)
M_ModifyCounter(5, 1)
M_ModifyCounter(6, 2)
M_ModifyCounter(7, 3)
If *IV
; Modify counter values
mov rcx, [p.p_Ctx]
mov rdx, [p.p_IV]
mov eax, [rdx]
mov edx, [rdx + 4]
XOr [rcx + 32], eax
XOr [rcx + 40], edx
XOr [rcx + 48], eax
XOr [rcx + 56], edx
rol edx, 16
xchg ax, dx
rol eax, 16
XOr [rcx + 36], eax
XOr [rcx + 44], edx
XOr [rcx + 52], eax
XOr [rcx + 60], edx
; Process 64 bytes
ProcessBytes(*Ctx, @M, @M, 64)
EndIf
EndProcedure
Procedure ProcessBytes(*Ctx.RabbitCtx, *Input, *Output, Size)
Protected.i reg_bx, reg_si, reg_di
If Size
mov [p.v_reg_bx], rbx
mov [p.v_reg_si], rsi
mov [p.v_reg_di], rdi
mov rcx, [p.p_Ctx] ; rcx = *Ctx
mov rsi, [p.p_Input] ; rsi = *Input
mov rdi, [p.p_Output] ; rdi = *Output
mov rbx, [p.v_Size] ; rbx = Size
sub rsp, 32 ; alloc g space
!.loop16b:
; Calculate new counter values
mov edx, [rcx + 64] ; load carry
shr edx, 1
M_AddWithCarry(0, 0x4d34d34d)
M_AddWithCarry(1, 0xd34d34d3)
M_AddWithCarry(2, 0x34d34d34)
M_AddWithCarry(3, 0x4d34d34d)
M_AddWithCarry(4, 0xd34d34d3)
M_AddWithCarry(5, 0x34d34d34)
M_AddWithCarry(6, 0x4d34d34d)
M_AddWithCarry(7, 0xd34d34d3)
adc edx, edx
mov [rcx + 64], edx ; save carry
; Calculate the g-functions
M_GFunction(0)
M_GFunction(1)
M_GFunction(2)
M_GFunction(3)
M_GFunction(4)
M_GFunction(5)
M_GFunction(6)
M_GFunction(7)
; Calculate new state values
M_NewStateValue(0, 7, 16, 6, 16)
M_NewStateValue(1, 0, 8, 7, 0)
M_NewStateValue(2, 1, 16, 0, 16)
M_NewStateValue(3, 2, 8, 1, 0)
M_NewStateValue(4, 3, 16, 2, 16)
M_NewStateValue(5, 4, 8, 3, 0)
M_NewStateValue(6, 5, 16, 4, 16)
M_NewStateValue(7, 6, 8, 5, 0)
; Xor stream bytes
sub rbx, 16
!jc .final
M_XorStreamBytes(0, 0, 5, 3)
M_XorStreamBytes(1, 2, 7, 5)
M_XorStreamBytes(2, 4, 1, 7)
M_XorStreamBytes(3, 6, 3, 1)
add rsi, 16
add rdi, 16
test rbx, rbx
!jnz .loop16b
!jmp .done
!.final:
M_XorStreamBytes(0, 0, 5, 3, 1)
M_XorStreamBytes(1, 2, 7, 5, 1)
M_XorStreamBytes(2, 4, 1, 7, 1)
M_XorStreamBytes(3, 6, 3, 1, 1)
add rbx, 15
!.loop1b:
movzx eax, byte [rsi + rbx]
XOr al, [rsp + rbx]
mov [rdi + rbx], al
sub rbx, 1
!jnc .loop1b
!.done:
add rsp, 32
mov rbx, [p.v_reg_bx]
mov rsi, [p.v_reg_si]
mov rdi, [p.v_reg_di]
EndIf
EndProcedure
Procedure CryptMemory(*Input, *Output, Size, *Key, *InitVector = #Null)
; Encrypt/decrypt a block of memory
; ---------------------------------
; *Key : Pointer to 128 bit key
; *IV : Pointer to 64 bit initialization vector
Protected Ctx.RabbitCtx
SetKeyAndIV(@Ctx, *Key, *InitVector)
ProcessBytes(@Ctx, *Input, *Output, Size)
EndProcedure
EndModule
Code: Select all
DataSection
; Test vectors
Key1:
Data.a $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
Out1:
Data.a $02,$F7,$4A,$1C,$26,$45,$6B,$F5,$EC,$D6,$A5,$36,$F0,$54,$57,$B1
Data.a $A7,$8A,$C6,$89,$47,$6C,$69,$7B,$39,$0C,$9C,$C5,$15,$D8,$E8,$88
Data.a $96,$D6,$73,$16,$88,$D1,$68,$DA,$51,$D4,$0C,$70,$C3,$A1,$16,$F4
Key2:
Data.a $C2,$1F,$CF,$38,$81,$CD,$5E,$E8,$62,$8A,$CC,$B0,$A9,$89,$0D,$F8
Out2:
Data.a $3D,$02,$E0,$C7,$30,$55,$91,$12,$B4,$73,$B7,$90,$DE,$E0,$18,$DF
Data.a $CD,$6D,$73,$0C,$E5,$4E,$19,$F0,$C3,$5E,$C4,$79,$0E,$B6,$C7,$4A
Data.a $B0,$BB,$1B,$B7,$86,$0A,$68,$5A,$BF,$9C,$8F,$AF,$26,$3C,$CA,$09
Key3:
Data.a $1D,$27,$2C,$6A,$2D,$8E,$3D,$FC,$AC,$14,$05,$6B,$78,$D6,$33,$A0
Out3:
Data.a $A3,$A9,$7A,$BB,$80,$39,$38,$20,$B7,$E5,$0C,$4A,$BB,$53,$82,$3D
Data.a $C4,$42,$37,$99,$C2,$EF,$C9,$FF,$B3,$A4,$12,$5F,$1F,$4C,$99,$A8
Data.a $AE,$95,$3E,$56,$D3,$8B,$D2,$67,$67,$C3,$64,$9E,$EF,$34,$D9,$19
Key4:
Data.a $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
IV4:
Data.a $00,$00,$00,$00,$00,$00,$00,$00
Out4:
Data.a $ED,$B7,$05,$67,$37,$5D,$CD,$7C,$D8,$95,$54,$F8,$5E,$27,$A7,$C6
Data.a $8D,$4A,$DC,$70,$32,$29,$8F,$7B,$D4,$EF,$F5,$04,$AC,$A6,$29,$5F
Data.a $66,$8F,$BF,$47,$8A,$DB,$2B,$E5,$1E,$6C,$DE,$29,$2B,$82,$DE,$2A
Key5:
Data.a $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
IV5:
Data.a $59,$7E,$26,$C1,$75,$F5,$73,$C3
Out5:
Data.a $6D,$7D,$01,$22,$92,$CC,$DC,$E0,$E2,$12,$00,$58,$B9,$4E,$CD,$1F
Data.a $2E,$6F,$93,$ED,$FF,$99,$24,$7B,$01,$25,$21,$D1,$10,$4E,$5F,$A7
Data.a $A7,$9B,$02,$12,$D0,$BD,$56,$23,$39,$38,$E7,$93,$C3,$12,$C1,$EB
Key6:
Data.a $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
IV6:
Data.a $27,$17,$F4,$D2,$1A,$56,$EB,$A6
Out6:
Data.a $4D,$10,$51,$A1,$23,$AF,$B6,$70,$BF,$8D,$85,$05,$C8,$D8,$5A,$44
Data.a $03,$5B,$C3,$AC,$C6,$67,$AE,$AE,$5B,$2C,$F4,$47,$79,$F2,$C8,$96
Data.a $CB,$51,$15,$F0,$34,$F0,$3D,$31,$17,$1C,$A7,$5F,$89,$FC,$CB,$9F
EndDataSection
Procedure VerifyTestVector(*Key, *IV, *Out, VectorName.s)
Protected Dim Stream.a(47)
Protected Ctx.Rabbit::RabbitCtx
Protected.i i, *a.Ascii = *Out
Rabbit::SetKeyAndIV(@Ctx, *Key, *IV)
Rabbit::ProcessBytes(@Ctx, @Stream(), @Stream(), 48)
For i = 0 To 47
If Stream(i) <> *a\a
Debug VectorName + " [ERROR]"
ProcedureReturn
EndIf
*a + 1
Next
Debug VectorName + " [ok]"
EndProcedure
VerifyTestVector(?Key1, #Null, ?Out1, "Vector 1")
VerifyTestVector(?Key2, #Null, ?Out2, "Vector 2")
VerifyTestVector(?Key3, #Null, ?Out3, "Vector 3")
VerifyTestVector(?Key4, ?IV4, ?Out4, "Vector 4")
VerifyTestVector(?Key5, ?IV5, ?Out5, "Vector 5")
VerifyTestVector(?Key6, ?IV6, ?Out6, "Vector 6")