// File: 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:
subq $0x82908, %rsp          # imm = 0x82908
movl $0x0, 0x82904(%rsp)
movl %edi, 0x82900(%rsp)
movq %rsi, 0x828f8(%rsp)
callq 0x45f0
testb $0x1, %al
jne 0x2dac
movq 0x426f(%rip), %rdi      # 0x6ff0
leaq 0x2388(%rip), %rsi      # 0x5110
callq 0x2100
movq %rax, %rdi
movq 0x4229(%rip), %rsi      # 0x6fc0
callq 0x2130
movl $0x1, 0x82904(%rsp)
jmp 0x32de
leaq 0x81570(%rsp), %rdi
movq %rdi, 0xa8(%rsp)
callq 0x3390
movq 0xa8(%rsp), %rdi
callq 0x3430
movl %eax, 0xb0(%rsp)
jmp 0x2dd7
movl 0xb0(%rsp), %eax
movl %eax, %eax
movl %eax, %esi
leaq 0x801e8(%rsp), %rdi
callq 0x3440
jmp 0x2df1
leaq 0x801d4(%rsp), %rdi
xorl %esi, %esi
movl $0xff, %edx
callq 0x3470
jmp 0x2e07
leaq 0x801c0(%rsp), %rax
movq %rax, 0x108(%rsp)
movq 0x108(%rsp), %rax
movq %rax, 0x100(%rsp)
movq 0x108(%rsp), %rax
addq $0x10, %rax
movq %rax, 0xf8(%rsp)
movq 0x100(%rsp), %rax
cmpq 0xf8(%rsp), %rax
je 0x2eca
movq 0x100(%rsp), %rax
movq %rax, 0xf0(%rsp)
leaq 0x801d4(%rsp), %rdi
leaq 0x801e8(%rsp), %rsi
callq 0x34a0
movl %eax, 0xa4(%rsp)
jmp 0x2e7b
movl 0xa4(%rsp), %eax
movb %al, %cl
movq 0xf0(%rsp), %rax
movb %cl, (%rax)
movq 0x100(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x100(%rsp)
jmp 0x2e3b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x801e0(%rsp)
movl %eax, 0x801dc(%rsp)
leaq 0x81570(%rsp), %rdi
callq 0x34d0
jmp 0x32ed
leaq 0x801c0(%rsp), %rdi
leaq 0x80110(%rsp), %rsi
callq 0x460a
jmp 0x2ee1
leaq 0x60110(%rsp), %rax
movq %rax, 0xe8(%rsp)
movq 0xe8(%rsp), %rax
movq %rax, 0xe0(%rsp)
movq 0xe8(%rsp), %rax
addq $0x20000, %rax          # imm = 0x20000
movq %rax, 0xd8(%rsp)
movq 0xe0(%rsp), %rax
cmpq 0xd8(%rsp), %rax
je 0x2f80
movq 0xe0(%rsp), %rax
movq %rax, 0xd0(%rsp)
leaq 0x801d4(%rsp), %rdi
leaq 0x801e8(%rsp), %rsi
callq 0x34a0
movl %eax, 0xa0(%rsp)
jmp 0x2f57
movl 0xa0(%rsp), %eax
movb %al, %cl
movq 0xd0(%rsp), %rax
movb %cl, (%rax)
movq 0xe0(%rsp), %rax
addq $0x1, %rax
movq %rax, 0xe0(%rsp)
jmp 0x2f17
leaq 0x80110(%rsp), %rdi
leaq 0x40110(%rsp), %rsi
leaq 0x60110(%rsp), %rdx
callq 0x2b40
movq %rax, 0x98(%rsp)
jmp 0x2fa7
movq 0x98(%rsp), %rax
movq %rax, 0xc8(%rsp)
leaq 0x80110(%rsp), %rdi
leaq 0x20110(%rsp), %rsi
leaq 0x60110(%rsp), %rdx
callq 0x2bf0
movq %rax, 0x90(%rsp)
jmp 0x2fde
movq 0x90(%rsp), %rax
movq %rax, 0xc0(%rsp)
leaq 0x80110(%rsp), %rdi
leaq 0x110(%rsp), %rsi
leaq 0x60110(%rsp), %rdx
callq 0x2ca0
movq %rax, 0x88(%rsp)
jmp 0x3015
movq 0x88(%rsp), %rax
movq %rax, 0xb8(%rsp)
movq 0x3fa4(%rip), %rdi      # 0x6fd0
leaq 0x20f9(%rip), %rsi      # 0x512c
callq 0x2100
movq %rax, 0x80(%rsp)
jmp 0x3042
movq 0x80(%rsp), %rdi
movl $0x10, %esi
callq 0x21b0
movq %rax, 0x78(%rsp)
jmp 0x305b
movq 0x78(%rsp), %rdi
movq 0x3f59(%rip), %rsi      # 0x6fc0
callq 0x2130
jmp 0x306e
movq 0x3f5b(%rip), %rdi      # 0x6fd0
leaq 0x20c1(%rip), %rsi      # 0x513d
callq 0x2100
movq %rax, 0x70(%rsp)
jmp 0x3088
movq 0x70(%rsp), %rdi
movl $0x2000, %esi           # imm = 0x2000
callq 0x21b0
movq %rax, 0x68(%rsp)
jmp 0x309e
movq 0x68(%rsp), %rdi
movq 0x3f16(%rip), %rsi      # 0x6fc0
callq 0x2130
jmp 0x30b1
movq 0x3f18(%rip), %rdi      # 0x6fd0
leaq 0x208f(%rip), %rsi      # 0x514e
callq 0x2100
movq %rax, 0x60(%rsp)
jmp 0x30cb
movq 0x60(%rsp), %rdi
movl $0x20000, %esi          # imm = 0x20000
callq 0x21b0
movq %rax, 0x58(%rsp)
jmp 0x30e1
movq 0x58(%rsp), %rdi
movq 0x3ed3(%rip), %rsi      # 0x6fc0
callq 0x2130
jmp 0x30f4
movq 0x3ed5(%rip), %rdi      # 0x6fd0
leaq 0x205d(%rip), %rsi      # 0x515f
callq 0x2100
movq %rax, 0x50(%rsp)
jmp 0x310e
movq 0x50(%rsp), %rdi
cvtsi2sdq 0xc8(%rsp), %xmm0
movsd 0x1ee3(%rip), %xmm1     # 0x5008
divsd %xmm1, %xmm0
callq 0x21e0
movq %rax, 0x48(%rsp)
jmp 0x3135
movq 0x48(%rsp), %rdi
leaq 0x202f(%rip), %rsi      # 0x5170
callq 0x2100
movq %rax, 0x40(%rsp)
jmp 0x314d
movq 0x40(%rsp), %rdi
movq 0x3e67(%rip), %rsi      # 0x6fc0
callq 0x2130
jmp 0x3160
movq 0x3e69(%rip), %rdi      # 0x6fd0
leaq 0x2006(%rip), %rsi      # 0x5174
callq 0x2100
movq %rax, 0x38(%rsp)
jmp 0x317a
movq 0x38(%rsp), %rdi
cvtsi2sdq 0xc0(%rsp), %xmm0
movsd 0x1e77(%rip), %xmm1     # 0x5008
divsd %xmm1, %xmm0
callq 0x21e0
movq %rax, 0x30(%rsp)
jmp 0x31a1
movq 0x30(%rsp), %rdi
leaq 0x1fc3(%rip), %rsi      # 0x5170
callq 0x2100
movq %rax, 0x28(%rsp)
jmp 0x31b9
movq 0x28(%rsp), %rdi
movq 0x3dfb(%rip), %rsi      # 0x6fc0
callq 0x2130
jmp 0x31cc
movq 0x3dfd(%rip), %rdi      # 0x6fd0
leaq 0x1fab(%rip), %rsi      # 0x5185
callq 0x2100
movq %rax, 0x20(%rsp)
jmp 0x31e6
movq 0x20(%rsp), %rdi
cvtsi2sdq 0xb8(%rsp), %xmm0
movsd 0x1e0b(%rip), %xmm1     # 0x5008
divsd %xmm1, %xmm0
callq 0x21e0
movq %rax, 0x18(%rsp)
jmp 0x320d
movq 0x18(%rsp), %rdi
leaq 0x1f57(%rip), %rsi      # 0x5170
callq 0x2100
movq %rax, 0x10(%rsp)
jmp 0x3225
movq 0x10(%rsp), %rdi
movq 0x3d8f(%rip), %rsi      # 0x6fc0
callq 0x2130
jmp 0x3238
leaq 0x40110(%rsp), %rdi
leaq 0x20110(%rsp), %rsi
movl $0x20000, %edx          # imm = 0x20000
callq 0x2090
cmpl $0x0, %eax
jne 0x3276
leaq 0x40110(%rsp), %rdi
leaq 0x110(%rsp), %rsi
movl $0x20000, %edx          # imm = 0x20000
callq 0x2090
cmpl $0x0, %eax
je 0x32bb
movq 0x3d73(%rip), %rdi      # 0x6ff0
leaq 0x1f12(%rip), %rsi      # 0x5196
callq 0x2100
movq %rax, 0x8(%rsp)
jmp 0x3290
movq 0x8(%rsp), %rdi
movq 0x3d24(%rip), %rsi      # 0x6fc0
callq 0x2130
jmp 0x32a3
movl $0x2, 0x82904(%rsp)
movl $0x1, 0xb4(%rsp)
jmp 0x32d1
movl $0x0, 0x82904(%rsp)
movl $0x1, 0xb4(%rsp)
leaq 0x81570(%rsp), %rdi
callq 0x34d0
movl 0x82904(%rsp), %eax
addq $0x82908, %rsp          # imm = 0x82908
retq
movq 0x801e0(%rsp), %rdi
callq 0x21c0
nopw (%rax,%rax)