// File: ushitora-anqou[P]aqtfhe2/main.cpp
// Function: void (anonymous namespace)::test_performance<aqtfhe2::params::CGGI16>()
void test_performance()
{
    using secret_key = aqtfhe2::secret_key<P>;
    using cloud_key = aqtfhe2::cloud_key<P>;
    using encrypted_bit = aqtfhe2::tlwe_lvl0<P>;

    std::random_device rand;
    auto sk = secret_key::make(rand);
    auto ck = cloud_key::make(rand, sk);

    const size_t TEST_SIZE = 1000;

    // Prepare plain data
    nd_array<bool, TEST_SIZE> p = random_bool_array<TEST_SIZE>(rand),
                              q = random_bool_array<TEST_SIZE>(rand), r;
    for (size_t i = 0; i < TEST_SIZE; i++)
        r[i] = !(p[i] & q[i]);

    // Encrypt the data
    std::vector<encrypted_bit> p_enc, q_enc, r_enc;
    for (bool v : p)
        p_enc.push_back(sk.encrypt(rand, v));
    for (bool v : q)
        q_enc.push_back(sk.encrypt(rand, v));
    r_enc.reserve(TEST_SIZE);

    // Calc NAND
    auto begin = std::chrono::high_resolution_clock::now();
    // ProfilerStart("sample.prof");
    for (size_t i = 0; i < TEST_SIZE; i++)
        r_enc.push_back(ck.nand(p_enc[i], q_enc[i]));
    // ProfilerStop();
    auto end = std::chrono::high_resolution_clock::now();

    // Print elapsed time.
    auto usec =
        std::chrono::duration_cast<std::chrono::microseconds>(end - begin);
    std::cerr << usec.count() / TEST_SIZE << "us / gate" << std::endl;

    // Check the results
    for (size_t i = 0; i < TEST_SIZE; i++)
        assert(r[i] == sk.decrypt(r_enc[i]));
}

// Assembly:
subq $0x4fe8, %rsp           # imm = 0x4FE8
leaq 0x3c60(%rsp), %rdi
movq %rdi, 0x60(%rsp)
callq 0x2fd0
movq 0x60(%rsp), %rsi
leaq 0x2490(%rsp), %rdi
callq 0x3070
jmp 0x24bd
leaq 0x2460(%rsp), %rdi
leaq 0x3c60(%rsp), %rsi
leaq 0x2490(%rsp), %rdx
callq 0x3250
jmp 0x24dc
movq $0x3e8, 0x2458(%rsp) # imm = 0x3E8
leaq 0x2070(%rsp), %rdi
leaq 0x3c60(%rsp), %rsi
callq 0x2f30
jmp 0x24ff
leaq 0x1c88(%rsp), %rdi
leaq 0x3c60(%rsp), %rsi
callq 0x2f30
jmp 0x2516
movq $0x0, 0x1898(%rsp)
cmpq $0x3e8, 0x1898(%rsp) # imm = 0x3E8
jae 0x2607
movq 0x1898(%rsp), %rsi
leaq 0x2070(%rsp), %rdi
callq 0x32c0
movq %rax, 0x58(%rsp)
jmp 0x2550
movq 0x58(%rsp), %rax
movzbl (%rax), %eax
andl $0x1, %eax
movl %eax, 0x4c(%rsp)
movq 0x1898(%rsp), %rsi
leaq 0x1c88(%rsp), %rdi
callq 0x32c0
movq %rax, 0x50(%rsp)
jmp 0x257b
movl 0x4c(%rsp), %ecx
movq 0x50(%rsp), %rax
movzbl (%rax), %eax
andl %ecx, %eax
testb $0x1, %al
sete %al
movb %al, 0x3f(%rsp)
movq 0x1898(%rsp), %rsi
leaq 0x18a0(%rsp), %rdi
callq 0x32c0
movq %rax, 0x40(%rsp)
jmp 0x25ae
movq 0x40(%rsp), %rax
movb 0x3f(%rsp), %cl
andb $0x1, %cl
movb %cl, (%rax)
movq 0x1898(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x1898(%rsp)
jmp 0x2522
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2488(%rsp)
movl %eax, 0x2484(%rsp)
jmp 0x29d9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2488(%rsp)
movl %eax, 0x2484(%rsp)
jmp 0x29cc
leaq 0x1880(%rsp), %rdi
callq 0x32f0
leaq 0x1868(%rsp), %rdi
callq 0x32f0
leaq 0x1850(%rsp), %rdi
callq 0x32f0
leaq 0x2070(%rsp), %rax
movq %rax, 0x1848(%rsp)
movq 0x1848(%rsp), %rdi
callq 0x3300
movq %rax, 0x1840(%rsp)
movq 0x1848(%rsp), %rdi
callq 0x3310
movq %rax, 0x1838(%rsp)
movq 0x1840(%rsp), %rax
cmpq 0x1838(%rsp), %rax
je 0x272d
movq 0x1840(%rsp), %rax
movb (%rax), %al
andb $0x1, %al
movb %al, 0x1837(%rsp)
movzbl 0x1837(%rsp), %ecx
andl $0x1, %ecx
leaq 0x1060(%rsp), %rdi
leaq 0x2490(%rsp), %rsi
leaq 0x3c60(%rsp), %rdx
callq 0x3350
jmp 0x26bb
leaq 0x1880(%rsp), %rdi
leaq 0x1060(%rsp), %rsi
callq 0x3320
jmp 0x26d2
jmp 0x26d4
movq 0x1840(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x1840(%rsp)
jmp 0x2668
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2488(%rsp)
movl %eax, 0x2484(%rsp)
leaq 0x1850(%rsp), %rdi
callq 0x35c0
leaq 0x1868(%rsp), %rdi
callq 0x35c0
leaq 0x1880(%rsp), %rdi
callq 0x35c0
jmp 0x29cc
leaq 0x1c88(%rsp), %rax
movq %rax, 0x1058(%rsp)
movq 0x1058(%rsp), %rdi
callq 0x3300
movq %rax, 0x1050(%rsp)
movq 0x1058(%rsp), %rdi
callq 0x3310
movq %rax, 0x1048(%rsp)
movq 0x1050(%rsp), %rax
cmpq 0x1048(%rsp), %rax
je 0x27e5
movq 0x1050(%rsp), %rax
movb (%rax), %al
andb $0x1, %al
movb %al, 0x1047(%rsp)
movzbl 0x1047(%rsp), %ecx
andl $0x1, %ecx
leaq 0x870(%rsp), %rdi
leaq 0x2490(%rsp), %rsi
leaq 0x3c60(%rsp), %rdx
callq 0x3350
jmp 0x27b6
leaq 0x1868(%rsp), %rdi
leaq 0x870(%rsp), %rsi
callq 0x3320
jmp 0x27cd
jmp 0x27cf
movq 0x1050(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x1050(%rsp)
jmp 0x2767
leaq 0x1850(%rsp), %rdi
movl $0x3e8, %esi            # imm = 0x3E8
callq 0x3390
jmp 0x27f9
callq 0x2030
movq %rax, 0x868(%rsp)
movq $0x0, 0x860(%rsp)
cmpq $0x3e8, 0x860(%rsp) # imm = 0x3E8
jae 0x28a4
movq 0x860(%rsp), %rsi
leaq 0x1880(%rsp), %rdi
callq 0x3510
movq %rax, 0x30(%rsp)
movq 0x860(%rsp), %rsi
leaq 0x1868(%rsp), %rdi
callq 0x3510
movq 0x30(%rsp), %rdx
movq %rax, %rcx
leaq 0x8c(%rsp), %rdi
leaq 0x2460(%rsp), %rsi
callq 0x34a0
jmp 0x2872
leaq 0x1850(%rsp), %rdi
leaq 0x8c(%rsp), %rsi
callq 0x3320
jmp 0x2889
jmp 0x288b
movq 0x860(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x860(%rsp)
jmp 0x2812
callq 0x2030
movq %rax, 0x80(%rsp)
leaq 0x80(%rsp), %rdi
leaq 0x868(%rsp), %rsi
callq 0x3560
movq %rax, 0x28(%rsp)
jmp 0x28cd
movq 0x28(%rsp), %rax
movq %rax, 0x70(%rsp)
leaq 0x70(%rsp), %rdi
callq 0x3530
movq %rax, 0x20(%rsp)
jmp 0x28e8
movq 0x20(%rsp), %rax
movq %rax, 0x78(%rsp)
leaq 0x78(%rsp), %rdi
callq 0x35b0
movq %rax, 0x18(%rsp)
jmp 0x2903
movq 0x18(%rsp), %rdx
shrq $0x3, %rdx
movabsq $0x20c49ba5e353f7cf, %rax # imm = 0x20C49BA5E353F7CF
mulxq %rax, %rsi, %rsi
shrq $0x4, %rsi
movq 0x1b6ca(%rip), %rdi     # 0x1dff0
callq 0x2060
movq %rax, 0x10(%rsp)
jmp 0x2932
movq 0x10(%rsp), %rdi
leaq 0x137c4(%rip), %rsi     # 0x16102
callq 0x21a0
movq %rax, 0x8(%rsp)
jmp 0x294a
movq 0x8(%rsp), %rdi
movq 0x1b672(%rip), %rsi     # 0x1dfc8
callq 0x21d0
jmp 0x295d
movq $0x0, 0x68(%rsp)
cmpq $0x3e8, 0x68(%rsp)      # imm = 0x3E8
jae 0x2983
jmp 0x2973
movq 0x68(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x68(%rsp)
jmp 0x2966
leaq 0x1850(%rsp), %rdi
callq 0x35c0
leaq 0x1868(%rsp), %rdi
callq 0x35c0
leaq 0x1880(%rsp), %rdi
callq 0x35c0
leaq 0x2460(%rsp), %rdi
callq 0x3620
leaq 0x3c60(%rsp), %rdi
callq 0x3650
addq $0x4fe8, %rsp           # imm = 0x4FE8
retq
leaq 0x2460(%rsp), %rdi
callq 0x3620
leaq 0x3c60(%rsp), %rdi
callq 0x3650
movq 0x2488(%rsp), %rdi
callq 0x2290
nopw %cs:(%rax,%rax)