// File: /workspace/github_cpp_makefile_star2_O2/dwkim606[P]IPPBA/main.cpp
// Function: main
int main() {
	
		long count = 0;
		
		double mskTime = 0.;
		double skTime = 0.;
		double encTime = 0.;
		double ipTime = 0.;
		
		int64_t ptxtResult;
		chrono::high_resolution_clock::time_point t1;
		chrono::high_resolution_clock::time_point t2;

		MasterSecretKey msk;
		EncryptedTemplate T;
		EncryptedBio B;

		Biometric X, Y;

		// Start Test
		cout << TEST_NUM << " iteration start!" << endl;
		for (long i = 0; i < TEST_NUM; i++) {
			printProgress((double)i / TEST_NUM);

			// Make template biometric
			for (long i = 0; i < K; i++) {
				X[i] = U(GEN) % 2;
				X[i] = 1 - 2 * X[i];
			}

			// Generate Master Secret Key
			t1 = chrono::high_resolution_clock::now();
			Scheme::mskGen(msk);
			t2 = chrono::high_resolution_clock::now();
			mskTime += chrono::duration_cast<chrono::milliseconds>(t2 - t1).count();
		
			// Generate Encryped Template corresponding to X
			t1 = chrono::high_resolution_clock::now();
			Scheme::templateGen(T, msk, X);
			t2 = chrono::high_resolution_clock::now();
			skTime += chrono::duration_cast<chrono::milliseconds>(t2 - t1).count();
					
			// Set random Y
			for (long j = 0; j < K; j++) {
				Y[j] = U(GEN) % 2;
				Y[j] = 1 - 2 * Y[j];
			}
			// Encrypt Bio information
			t1 = chrono::high_resolution_clock::now();
			Scheme::encryptBio(B, msk, Y);
			t2 = chrono::high_resolution_clock::now();
			encTime += chrono::duration_cast<chrono::milliseconds>(t2 - t1).count();
			// Compute Result in un-encrypted state for check
			ptxtResult = 0;
			for (long j = 0; j < K; j++) {
				ptxtResult += X[j] * Y[j];
			}
			// InnerProduct using encrypted template T and encrypted bio B
			t1 = chrono::high_resolution_clock::now();
			int64_t result = Scheme::innerProduct(T, B);
			t2 = chrono::high_resolution_clock::now();
			ipTime += chrono::duration_cast<chrono::microseconds>(t2 - t1).count();
			// Check the result
			if (ptxtResult != result) {
				cout << ptxtResult << endl;
				cout << result << endl;
				cout << "  " << endl;
				count++;
				cout << i << "-th running has ERROR!!!" << endl;
			}
		}

		cout << endl;
		cout << "- Master Secret Key Generation Time: " << mskTime / TEST_NUM << " ms" << endl;
		cout << "- Template Generation Time: " << skTime / TEST_NUM << " ms" << endl;

		if (count == 0) cout << "No error occured." << endl;
		cout << "- Average Time for Encryption: " << encTime / TEST_NUM << " ms" << endl;
		cout << "- Average Time for InnerProduct: " << ipTime / TEST_NUM << " us" << endl;
		cout << "- Error Rate: " << 100 * (double)count / TEST_NUM << "%" << endl;


		delete[] msk.S;
		delete[] msk.U;



	cout << "PRESS ENTER to EXIT" << endl;
	cin.ignore();
	return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x47adb8, %rsp         # imm = 0x47ADB8
leaq 0x40(%rsp), %r12
movq %r12, %rdi
callq 0x2982
movq 0x3b2f(%rip), %rdi      # 0x5fd0
pushq $0x64
popq %rsi
callq 0x21b0
leaq 0x1bb6(%rip), %rsi      # 0x4066
movq %rax, %rdi
callq 0x2140
movq %rax, %rdi
callq 0x20a0
xorpd %xmm0, %xmm0
movsd %xmm0, 0x20(%rsp)
xorl %ebx, %ebx
movsd 0x1b34(%rip), %xmm1     # 0x4008
movl $0xf4240, %ebp          # imm = 0xF4240
leaq 0x5990(%rip), %r13      # 0x7e70
leaq 0x4fc1(%rip), %r14      # 0x74a8
pushq $0x1
popq %r15
movsd %xmm0, 0x18(%rsp)
movsd %xmm0, 0x10(%rsp)
movsd %xmm0, 0x8(%rsp)
movq $0x0, 0x28(%rsp)
cmpq $0x64, %rbx
je 0x2751
movq %rbx, 0x30(%rsp)
cvtsi2sd %rbx, %xmm0
divsd %xmm1, %xmm0
callq 0x242c
xorl %ebx, %ebx
cmpq $0x239a8, %rbx          # imm = 0x239A8
je 0x2551
movq %r13, %rdi
movq %r14, %rsi
callq 0x29a4
addl %eax, %eax
andl $0x2, %eax
movq %r15, %rcx
subq %rax, %rcx
movq %rcx, 0x11cd90(%rsp,%rbx,8)
incq %rbx
jmp 0x2525
callq 0x2050
movq %rax, %rbx
movq %r12, %rdi
callq 0x2ca4
callq 0x2050
subq %rbx, %rax
cqto
idivq %rbp
cvtsi2sd %rax, %xmm0
movsd %xmm0, (%rsp)
callq 0x2050
movq %rax, %rbx
leaq 0x239ad0(%rsp), %rdi
movq %r12, %rsi
leaq 0x11cd90(%rsp), %rdx
callq 0x2d43
callq 0x2050
subq %rbx, %rax
cqto
idivq %rbp
cvtsi2sd %rax, %xmm0
movsd %xmm0, 0x38(%rsp)
xorl %ebx, %ebx
cmpq $0x239a8, %rbx          # imm = 0x239A8
je 0x25db
movq %r13, %rdi
movq %r14, %rsi
callq 0x29a4
addl %eax, %eax
andl $0x2, %eax
movq %r15, %rcx
subq %rax, %rcx
movq %rcx, 0x50(%rsp,%rbx,8)
incq %rbx
jmp 0x25b2
movsd 0x8(%rsp), %xmm0
addsd (%rsp), %xmm0
movsd %xmm0, 0x8(%rsp)
callq 0x2050
movq %rax, %rbx
leaq 0x35a440(%rsp), %rdi
movq %r12, %rsi
leaq 0x50(%rsp), %rdx
callq 0x2db4
callq 0x2050
subq %rbx, %rax
cqto
idivq %rbp
cvtsi2sd %rax, %xmm0
movsd %xmm0, (%rsp)
xorl %ebp, %ebp
xorl %eax, %eax
cmpq $0x239a8, %rax          # imm = 0x239A8
je 0x2642
movq 0x50(%rsp,%rax,8), %rcx
imulq 0x11cd90(%rsp,%rax,8), %rcx
addq %rcx, %rbp
incq %rax
jmp 0x2624
callq 0x2050
movq %rax, %r12
leaq 0x239ad0(%rsp), %rdi
leaq 0x35a440(%rsp), %rsi
callq 0x2efb
movq %rax, %rbx
callq 0x2050
subq %r12, %rax
cqto
movl $0x3e8, %ecx            # imm = 0x3E8
idivq %rcx
movq %rax, %r12
cmpq %rbx, %rbp
jne 0x268b
movsd 0x1984(%rip), %xmm1     # 0x4008
movq 0x30(%rsp), %rbx
jmp 0x2707
movq 0x393e(%rip), %rdi      # 0x5fd0
movq %rbp, %rsi
callq 0x2130
movq %rax, %rdi
callq 0x20a0
movq 0x3927(%rip), %rbp      # 0x5fd0
movq %rbp, %rdi
movq %rbx, %rsi
callq 0x2130
movq %rax, %rdi
callq 0x20a0
movq %rbp, %rdi
leaq 0x19b2(%rip), %rsi      # 0x4078
callq 0x2140
movq %rax, %rdi
callq 0x20a0
incq 0x28(%rsp)
movq %rbp, %rdi
movq 0x30(%rsp), %rbx
movq %rbx, %rsi
callq 0x2130
movq %rax, %rdi
leaq 0x1989(%rip), %rsi      # 0x407b
callq 0x2140
movq %rax, %rdi
callq 0x20a0
movsd 0x1901(%rip), %xmm1     # 0x4008
movl $0xf4240, %ebp          # imm = 0xF4240
movsd 0x10(%rsp), %xmm0
addsd 0x38(%rsp), %xmm0
movsd %xmm0, 0x10(%rsp)
movsd 0x18(%rsp), %xmm0
addsd (%rsp), %xmm0
movsd %xmm0, 0x18(%rsp)
cvtsi2sd %r12, %xmm0
movsd 0x20(%rsp), %xmm2
addsd %xmm0, %xmm2
movsd %xmm2, 0x20(%rsp)
incq %rbx
leaq 0x40(%rsp), %r12
jmp 0x2506
movq 0x3878(%rip), %rbx      # 0x5fd0
movq %rbx, %rdi
callq 0x20a0
leaq 0x192d(%rip), %rsi      # 0x4094
movq %rbx, %rdi
callq 0x2140
movsd 0x8(%rsp), %xmm0
divsd 0x188b(%rip), %xmm0     # 0x4008
movq %rax, %rdi
callq 0x2190
leaq 0x192e(%rip), %r14      # 0x40ba
movq %rax, %rdi
movq %r14, %rsi
callq 0x2140
movq %rax, %rdi
callq 0x20a0
leaq 0x1918(%rip), %rsi      # 0x40be
movq %rbx, %rdi
callq 0x2140
movsd 0x10(%rsp), %xmm0
divsd 0x184c(%rip), %xmm0     # 0x4008
movq %rax, %rdi
callq 0x2190
movq %rax, %rdi
movq %r14, %rsi
callq 0x2140
movq %rax, %rdi
callq 0x20a0
movq 0x28(%rsp), %r14
testq %r14, %r14
jne 0x27fc
movq 0x37e8(%rip), %rdi      # 0x5fd0
leaq 0x18ec(%rip), %rsi      # 0x40db
callq 0x2140
movq %rax, %rdi
callq 0x20a0
movq 0x37cd(%rip), %rbx      # 0x5fd0
leaq 0x18e3(%rip), %rsi      # 0x40ed
movq %rbx, %rdi
callq 0x2140
movsd 0x18(%rsp), %xmm0
movsd 0x17e8(%rip), %xmm1     # 0x4008
divsd %xmm1, %xmm0
movq %rax, %rdi
callq 0x2190
leaq 0x1887(%rip), %rsi      # 0x40ba
movq %rax, %rdi
callq 0x2140
movq %rax, %rdi
callq 0x20a0
leaq 0x18c3(%rip), %rsi      # 0x410d
movq %rbx, %rdi
callq 0x2140
movsd 0x20(%rsp), %xmm0
divsd 0x17a8(%rip), %xmm0     # 0x4008
movq %rax, %rdi
callq 0x2190
leaq 0x18c0(%rip), %rsi      # 0x412f
movq %rax, %rdi
callq 0x2140
movq %rax, %rdi
callq 0x20a0
leaq 0x18ad(%rip), %rsi      # 0x4133
movq %rbx, %rdi
callq 0x2140
cvtsi2sd %r14, %xmm0
movsd 0x176d(%rip), %xmm1     # 0x4008
mulsd %xmm1, %xmm0
divsd %xmm1, %xmm0
movq %rax, %rdi
callq 0x2190
leaq 0x1890(%rip), %rsi      # 0x4142
movq %rax, %rdi
callq 0x2140
movq %rax, %rdi
callq 0x20a0
movq 0x40(%rsp), %rdi
testq %rdi, %rdi
je 0x28d1
callq 0x2160
movq 0x48(%rsp), %rdi
testq %rdi, %rdi
je 0x28e0
callq 0x2160
movq 0x36e9(%rip), %rdi      # 0x5fd0
leaq 0x1856(%rip), %rsi      # 0x4144
callq 0x2140
movq %rax, %rdi
callq 0x20a0
movq 0x36de(%rip), %rdi      # 0x5fe0
callq 0x21e0
xorl %eax, %eax
addq $0x47adb8, %rsp         # imm = 0x47ADB8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nop