// File: /workspace/github_cpp_makefile_star2_O2/bakeunbin[P]inverse_mix_column_precalculated/invmc.cpp
// Function: main
int main (int argc, char * argv [])
{
	if (not check_aes_ni_support ())
	{
		std::cerr << "Cannot test without AES-NI." << std::endl;
		return 1;
	}

	std::random_device rd;
	std::mt19937 mt (rd ());
	std::uniform_int_distribution <uint32_t> dist (0, 255);
	
	// AES-ECB-128
	uint8_t key [BLOCK_SIZE], obj [AES_128_KEY_OBJ_SIZE];
	uint8_t input [VECTOR_SIZE];
	uint8_t fullni [VECTOR_SIZE], precalc [VECTOR_SIZE], gmul [VECTOR_SIZE];

	for (auto & k : key)
	{
		k = (uint8_t) dist (mt);
	}

	aesni_keygen (key, obj);
	
	for (auto & i : input)
	{
		i = (uint8_t) dist (mt);
	}

	auto fullni_t = decrypt_full_aesni (obj, fullni, input);
	auto precalc_t = decrypt_mixed_precalc (obj, precalc, input);
	auto gmul_t = decrypt_mixed_gmul (obj, gmul, input);

	std::cout << "Block size    : " << BLOCK_SIZE << std::endl;
	std::cout << "Block count   : " << BLOCK_COUNT << std::endl;
	std::cout << "Vector size   : " << VECTOR_SIZE << std::endl;
	std::cout << "AES-NI        : " << (fullni_t / 1000.0) << "μs" << std::endl;
	std::cout << "Soft Precalc  : " << (precalc_t / 1000.0) << "μs" << std::endl;
	std::cout << "Soft GMul     : " << (gmul_t / 1000.0) << "μs" << std::endl;

	if (memcmp (fullni, precalc, VECTOR_SIZE) or memcmp (fullni, gmul, VECTOR_SIZE))
	{
		std::cerr << "Test result invalid: results different from AES-NI." << std::endl;
		return 2;
	}

	return 0;
}

// Assembly:
pushq %r15
pushq %r14
pushq %r12
pushq %rbx
subq $0x827e8, %rsp          # imm = 0x827E8
callq 0x2f50
testb %al, %al
je 0x2871
leaq 0x1458(%rsp), %rbx
movq %rbx, %rdi
callq 0x2afc
movq %rbx, %rdi
callq 0x2120
movl %eax, %esi
leaq 0xd0(%rsp), %rdi
callq 0x2cd4
movabsq $0xff00000000, %rax     # imm = 0xFF00000000
leaq 0x8(%rsp), %rbx
movq %rax, (%rbx)
xorl %r15d, %r15d
leaq 0xd0(%rsp), %r14
cmpq $0x10, %r15
je 0x2894
movq %rbx, %rdi
movq %r14, %rsi
callq 0x2b52
movb %al, 0x10(%rsp,%r15)
incq %r15
jmp 0x2856
movq 0x3778(%rip), %rdi      # 0x5ff0
leaq 0x1891(%rip), %rsi      # 0x4110
callq 0x20e0
movq %rax, %rdi
callq 0x2080
pushq $0x1
popq %rbx
jmp 0x2ac4
leaq 0x10(%rsp), %rdi
leaq 0x20(%rsp), %rsi
callq 0x2f6a
xorl %r15d, %r15d
leaq 0x8(%rsp), %rbx
leaq 0xd0(%rsp), %r14
cmpq $0x20000, %r15          # imm = 0x20000
je 0x28d4
movq %rbx, %rdi
movq %r14, %rsi
callq 0x2b52
movb %al, 0x227e0(%rsp,%r15)
incq %r15
jmp 0x28b3
leaq 0x20(%rsp), %rdi
leaq 0x27e0(%rsp), %rsi
leaq 0x227e0(%rsp), %rdx
callq 0x26ea
movq %rax, %r15
leaq 0x20(%rsp), %rbx
leaq 0x627e0(%rsp), %rsi
leaq 0x227e0(%rsp), %r12
movq %rbx, %rdi
movq %r12, %rdx
callq 0x2745
movq %rax, %r14
leaq 0x427e0(%rsp), %rsi
movq %rbx, %rdi
movq %r12, %rdx
callq 0x27a0
movq %rax, %rbx
movq 0x369f(%rip), %rdi      # 0x5fd0
leaq 0x17f4(%rip), %rsi      # 0x412c
callq 0x20e0
pushq $0x10
popq %rsi
movq %rax, %rdi
callq 0x2160
movq %rax, %rdi
callq 0x2080
movq 0x3679(%rip), %rdi      # 0x5fd0
leaq 0x17df(%rip), %rsi      # 0x413d
callq 0x20e0
movq %rax, %rdi
movl $0x2000, %esi           # imm = 0x2000
callq 0x2160
movq %rax, %rdi
callq 0x2080
movq 0x3651(%rip), %rdi      # 0x5fd0
leaq 0x17c8(%rip), %rsi      # 0x414e
callq 0x20e0
movq %rax, %rdi
movl $0x20000, %esi          # imm = 0x20000
callq 0x2160
movq %rax, %rdi
callq 0x2080
movq 0x3629(%rip), %rdi      # 0x5fd0
leaq 0x17b1(%rip), %rsi      # 0x415f
callq 0x20e0
cvtsi2sd %r15, %xmm0
divsd 0x1648(%rip), %xmm0     # 0x4008
movq %rax, %rdi
callq 0x2140
leaq 0x17a1(%rip), %rsi      # 0x4170
movq %rax, %rdi
callq 0x20e0
movq %rax, %rdi
callq 0x2080
movq 0x35ea(%rip), %rdi      # 0x5fd0
leaq 0x1787(%rip), %rsi      # 0x4174
callq 0x20e0
cvtsi2sd %r14, %xmm0
divsd 0x1609(%rip), %xmm0     # 0x4008
movq %rax, %rdi
callq 0x2140
leaq 0x1762(%rip), %rsi      # 0x4170
movq %rax, %rdi
callq 0x20e0
movq %rax, %rdi
callq 0x2080
movq 0x35ab(%rip), %rdi      # 0x5fd0
leaq 0x1759(%rip), %rsi      # 0x4185
callq 0x20e0
cvtsi2sd %rbx, %xmm0
divsd 0x15ca(%rip), %xmm0     # 0x4008
movq %rax, %rdi
callq 0x2140
leaq 0x1723(%rip), %rsi      # 0x4170
movq %rax, %rdi
callq 0x20e0
movq %rax, %rdi
callq 0x2080
leaq 0x27e0(%rsp), %rdi
leaq 0x627e0(%rsp), %rsi
movl $0x20000, %edx          # imm = 0x20000
callq 0x2110
testl %eax, %eax
jne 0x2a99
leaq 0x27e0(%rsp), %rdi
leaq 0x427e0(%rsp), %rsi
movl $0x20000, %edx          # imm = 0x20000
callq 0x2110
testl %eax, %eax
je 0x2ad5
movq 0x3550(%rip), %rdi      # 0x5ff0
leaq 0x16ef(%rip), %rsi      # 0x4196
callq 0x20e0
movq %rax, %rdi
callq 0x2080
pushq $0x2
popq %rbx
leaq 0x1458(%rsp), %rdi
callq 0x2b5a
movl %ebx, %eax
addq $0x827e8, %rsp          # imm = 0x827E8
popq %rbx
popq %r12
popq %r14
popq %r15
retq
xorl %ebx, %ebx
jmp 0x2ab7
jmp 0x2ae3
jmp 0x2ae3
jmp 0x2ae3
jmp 0x2ae3
jmp 0x2ae3
movq %rax, %rbx
leaq 0x1458(%rsp), %rdi
callq 0x2b5a
movq %rbx, %rdi
callq 0x2170
nop