// File: /workspace/github_cpp_makefile_star2_O2/cgvwzq[P]aes_bf/src/aes-brute-force.cpp
// Function: aes_brute_force::search(voffset, unsigned char*, unsigned char*, unsigned char*, unsigned char*, unsigned char*, unsigned long&, bool&)
static
	void search(voffset_t v, uint8_t cipher[16], uint8_t key[16], uint8_t iv[16], uint8_t plain_mask[16], uint8_t plain[16], uint64_t &aes_cnt, bool &found)
	{
		uint8_t r[16];
		uint64_t n_loops = 1 << v.n_offsets; // iterate over all offsets combinations 
		found = false;
		__m128i key_schedule[20] = {0};
		aes128_load_key (key, key_schedule);
		aes_cnt = 0;

		for (uint64_t cnt=1; cnt < n_loops; cnt++)
		{
			// create index of offsets. more elegant with hamming weight and binary operations...
			uint8_t index[16] = {0}, ones = 0;
			for (uint8_t i=0; i < v.n_offsets; i++)
			{
				if (cnt & (1 << i))
				{
					index[ones++] = i;
				}
			}
			uint64_t n_chars = std::pow(v.n_valid_chars, ones);
			for (uint64_t c=0; c < n_chars; c++)
			{
				uint64_t t = c;
				for (uint8_t o=0; o < ones; o++)
				{
					cipher[v.offsets[index[o]]] = v.valid_chars[index[o]][t % v.n_valid_chars];
					t = t / v.n_valid_chars;
					
				}
				aes128_dec (key_schedule, cipher, r);
				#ifndef PADDING
					if (is_valid_plaintext (r, plain_mask, plain, iv))
				#else
					if (is_valid_plaintext_padding (r, plain_mask, plain, iv))
				#endif
				{
					found = true;
					done = true;
					return;
				}
				aes_cnt++;
				if (debug && !((aes_cnt+1) % 300000000))
				{
					println_128 ("\t(debug): ", cipher);
				}
			}
		}
	}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x1b8, %rsp            # imm = 0x1B8
leaq 0x1f0(%rsp), %r15
movq %rcx, 0x30(%rsp)
movq 0x1218(%rsp), %rcx
movq %rdx, 0x28(%rsp)
movq %r9, %rbx
movq %r8, 0x38(%rsp)
movq %rsi, %rdx
movq %rdi, %r13
movzbl 0x10(%r15), %r12d
pushq $0x1
popq %rax
shlxl %r12d, %eax, %eax
vxorpd %xmm0, %xmm0, %xmm0
leaq 0x70(%rsp), %rsi
movb $0x0, (%rcx)
movq %rdx, %rdi
movslq %eax, %r14
vmovupd %zmm0, 0x100(%rsi)
vmovupd %zmm0, 0xc0(%rsi)
vmovupd %zmm0, 0x80(%rsi)
vmovupd %zmm0, 0x40(%rsi)
vmovupd %zmm0, (%rsi)
vzeroupper
callq 0x3087
andq $0x0, (%rbx)
movq %rbx, 0x20(%rsp)
leaq 0x201(%rsp), %rbx
movzbl 0x1011(%r15), %ebp
vcvtsi2sd %ebp, %xmm1, %xmm0
pushq $0x1
popq %rdi
movl %r12d, 0x4(%rsp)
movq %r14, 0x10(%rsp)
vmovsd %xmm0, 0x8(%rsp)
cmpq %r14, %rdi
jae 0x3b54
vxorps %xmm1, %xmm1, %xmm1
xorl %eax, %eax
xorl %ecx, %ecx
vmovaps %xmm1, 0x50(%rsp)
pushq $0x1
popq %rsi
movzbl %cl, %r14d
cmpl %eax, %r12d
je 0x3a5b
shlxl %eax, %esi, %edx
movslq %edx, %rdx
testq %rdx, %rdi
je 0x3a57
leal 0x1(%r14), %ecx
movb %al, 0x50(%rsp,%r14)
incl %eax
jmp 0x3a38
movq %rdi, 0x18(%rsp)
movl %r14d, %edi
callq 0x21b0
vcvttsd2usi %xmm0, %rax
movq %rax, 0x40(%rsp)
xorl %eax, %eax
cmpq 0x40(%rsp), %rax
je 0x3b25
xorl %ecx, %ecx
movq %rax, 0x48(%rsp)
cmpq %rcx, %r14
je 0x3aae
movzbl 0x50(%rsp,%rcx), %esi
xorl %edx, %edx
divq %rbp
incq %rcx
movzbl (%r15,%rsi), %edi
shll $0x8, %esi
addq %rbx, %rsi
movb (%rdx,%rsi), %dl
movb %dl, (%r13,%rdi)
jmp 0x3a87
leaq 0x60(%rsp), %r12
leaq 0x70(%rsp), %rdi
movq %r13, %rsi
movq %r12, %rdx
callq 0x334d
movq 0x30(%rsp), %rsi
movq 0x38(%rsp), %rdx
movq 0x28(%rsp), %rcx
movq %r12, %rdi
callq 0x3b66
testb %al, %al
jne 0x3b42
movq 0x20(%rsp), %rdx
movq (%rdx), %rax
leaq 0x1(%rax), %rcx
movq %rcx, (%rdx)
cmpb $0x1, 0x3614(%rip)      # 0x7108
jne 0x3b18
addq $0x2, %rax
movl $0x11e1a300, %ecx       # imm = 0x11E1A300
xorl %edx, %edx
divq %rcx
testq %rdx, %rdx
jne 0x3b18
leaq 0x943(%rip), %rdi       # 0x4453
movq %r13, %rsi
callq 0x32e8
movq 0x48(%rsp), %rax
incq %rax
jmp 0x3a75
vmovsd 0x8(%rsp), %xmm0
movq 0x18(%rsp), %rdi
movl 0x4(%rsp), %r12d
movq 0x10(%rsp), %r14
incq %rdi
jmp 0x3a1e
movq 0x1218(%rsp), %rcx
movb $0x1, %al
movb %al, (%rcx)
movb %al, 0x35c6(%rip)       # 0x711a
addq $0x1b8, %rsp            # imm = 0x1B8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq