// File: 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
movq %rsp, %rbp
subq $0x47ae70, %rsp         # imm = 0x47AE70
movl $0x0, -0x4(%rbp)
movq $0x0, -0x10(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0x18(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0x20(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0x28(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0x30(%rbp)
leaq -0x40(%rbp), %rdi
callq 0x2f40
leaq -0x48(%rbp), %rdi
callq 0x2f40
leaq -0x58(%rbp), %rdi
callq 0x2f70
movq 0x58f4(%rip), %rdi      # 0x7fd0
movl $0x64, %esi
callq 0x2230
movq %rax, %rdi
leaq 0x2986(%rip), %rsi      # 0x5076
callq 0x2150
movq %rax, %rdi
movq 0x58c1(%rip), %rsi      # 0x7fc0
callq 0x2160
movq $0x0, -0x47adb8(%rbp)
cmpq $0x64, -0x47adb8(%rbp)
jge 0x2b69
cvtsi2sdq -0x47adb8(%rbp), %xmm0
movsd 0x28f2(%rip), %xmm1     # 0x5020
divsd %xmm1, %xmm0
callq 0x2600
movq $0x0, -0x47adc0(%rbp)
cmpq $0x239a8, -0x47adc0(%rbp) # imm = 0x239A8
jge 0x27b5
leaq 0x7782(%rip), %rdi      # 0x9ed8
leaq 0x6db3(%rip), %rsi      # 0x9510
callq 0x2fc0
movq %rax, %rcx
andq $0x1, %rcx
movq -0x47adc0(%rbp), %rax
movq %rcx, -0x35e070(%rbp,%rax,8)
movq -0x47adc0(%rbp), %rax
movq -0x35e070(%rbp,%rax,8), %rax
shlq %rax
movl $0x1, %ecx
subq %rax, %rcx
movq -0x47adc0(%rbp), %rax
movq %rcx, -0x35e070(%rbp,%rax,8)
movq -0x47adc0(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x47adc0(%rbp)
jmp 0x2742
callq 0x2050
movq %rax, -0x47adc8(%rbp)
movq -0x47adc8(%rbp), %rax
movq %rax, -0x40(%rbp)
leaq -0x58(%rbp), %rdi
callq 0x3cd0
callq 0x2050
movq %rax, -0x47add0(%rbp)
movq -0x47add0(%rbp), %rax
movq %rax, -0x48(%rbp)
leaq -0x48(%rbp), %rdi
leaq -0x40(%rbp), %rsi
callq 0x3020
movq %rax, -0x47ade0(%rbp)
leaq -0x47ade0(%rbp), %rdi
callq 0x2ff0
movq %rax, -0x47add8(%rbp)
leaq -0x47add8(%rbp), %rdi
callq 0x3070
cvtsi2sd %rax, %xmm0
addsd -0x18(%rbp), %xmm0
movsd %xmm0, -0x18(%rbp)
callq 0x2050
movq %rax, -0x47ade8(%rbp)
movq -0x47ade8(%rbp), %rax
movq %rax, -0x40(%rbp)
leaq -0x1209c0(%rbp), %rdi
leaq -0x58(%rbp), %rsi
leaq -0x35e070(%rbp), %rdx
callq 0x3da0
callq 0x2050
movq %rax, -0x47adf0(%rbp)
movq -0x47adf0(%rbp), %rax
movq %rax, -0x48(%rbp)
leaq -0x48(%rbp), %rdi
leaq -0x40(%rbp), %rsi
callq 0x3020
movq %rax, -0x47ae00(%rbp)
leaq -0x47ae00(%rbp), %rdi
callq 0x2ff0
movq %rax, -0x47adf8(%rbp)
leaq -0x47adf8(%rbp), %rdi
callq 0x3070
cvtsi2sd %rax, %xmm0
addsd -0x20(%rbp), %xmm0
movsd %xmm0, -0x20(%rbp)
movq $0x0, -0x47ae08(%rbp)
cmpq $0x239a8, -0x47ae08(%rbp) # imm = 0x239A8
jge 0x2933
leaq 0x7604(%rip), %rdi      # 0x9ed8
leaq 0x6c35(%rip), %rsi      # 0x9510
callq 0x2fc0
movq %rax, %rcx
andq $0x1, %rcx
movq -0x47ae08(%rbp), %rax
movq %rcx, -0x47adb0(%rbp,%rax,8)
movq -0x47ae08(%rbp), %rax
movq -0x47adb0(%rbp,%rax,8), %rax
shlq %rax
movl $0x1, %ecx
subq %rax, %rcx
movq -0x47ae08(%rbp), %rax
movq %rcx, -0x47adb0(%rbp,%rax,8)
movq -0x47ae08(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x47ae08(%rbp)
jmp 0x28c0
callq 0x2050
movq %rax, -0x47ae10(%rbp)
movq -0x47ae10(%rbp), %rax
movq %rax, -0x40(%rbp)
leaq -0x241330(%rbp), %rdi
leaq -0x58(%rbp), %rsi
leaq -0x47adb0(%rbp), %rdx
callq 0x3eb0
callq 0x2050
movq %rax, -0x47ae18(%rbp)
movq -0x47ae18(%rbp), %rax
movq %rax, -0x48(%rbp)
leaq -0x48(%rbp), %rdi
leaq -0x40(%rbp), %rsi
callq 0x3020
movq %rax, -0x47ae28(%rbp)
leaq -0x47ae28(%rbp), %rdi
callq 0x2ff0
movq %rax, -0x47ae20(%rbp)
leaq -0x47ae20(%rbp), %rdi
callq 0x3070
cvtsi2sd %rax, %xmm0
addsd -0x28(%rbp), %xmm0
movsd %xmm0, -0x28(%rbp)
movq $0x0, -0x38(%rbp)
movq $0x0, -0x47ae30(%rbp)
cmpq $0x239a8, -0x47ae30(%rbp) # imm = 0x239A8
jge 0x2a15
movq -0x47ae30(%rbp), %rax
movq -0x35e070(%rbp,%rax,8), %rax
movq -0x47ae30(%rbp), %rcx
imulq -0x47adb0(%rbp,%rcx,8), %rax
addq -0x38(%rbp), %rax
movq %rax, -0x38(%rbp)
movq -0x47ae30(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x47ae30(%rbp)
jmp 0x29cd
callq 0x2050
movq %rax, -0x47ae38(%rbp)
movq -0x47ae38(%rbp), %rax
movq %rax, -0x40(%rbp)
leaq -0x1209c0(%rbp), %rdi
leaq -0x241330(%rbp), %rsi
callq 0x40d0
movq %rax, -0x47ae40(%rbp)
callq 0x2050
movq %rax, -0x47ae48(%rbp)
movq -0x47ae48(%rbp), %rax
movq %rax, -0x48(%rbp)
leaq -0x48(%rbp), %rdi
leaq -0x40(%rbp), %rsi
callq 0x3020
movq %rax, -0x47ae58(%rbp)
leaq -0x47ae58(%rbp), %rdi
callq 0x3090
movq %rax, -0x47ae50(%rbp)
leaq -0x47ae50(%rbp), %rdi
callq 0x30c0
cvtsi2sd %rax, %xmm0
addsd -0x30(%rbp), %xmm0
movsd %xmm0, -0x30(%rbp)
movq -0x38(%rbp), %rax
cmpq -0x47ae40(%rbp), %rax
je 0x2b50
movq -0x38(%rbp), %rsi
movq 0x5515(%rip), %rdi      # 0x7fd0
callq 0x2290
movq %rax, %rdi
movq 0x54f6(%rip), %rsi      # 0x7fc0
callq 0x2160
movq -0x47ae40(%rbp), %rsi
movq 0x54f3(%rip), %rdi      # 0x7fd0
callq 0x2290
movq %rax, %rdi
movq 0x54d4(%rip), %rsi      # 0x7fc0
callq 0x2160
movq 0x54d8(%rip), %rdi      # 0x7fd0
leaq 0x2589(%rip), %rsi      # 0x5088
callq 0x2150
movq %rax, %rdi
movq 0x54b2(%rip), %rsi      # 0x7fc0
callq 0x2160
movq -0x10(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x10(%rbp)
movq -0x47adb8(%rbp), %rsi
movq 0x54a3(%rip), %rdi      # 0x7fd0
callq 0x2290
movq %rax, %rdi
leaq 0x254f(%rip), %rsi      # 0x508b
callq 0x2150
movq %rax, %rdi
movq 0x5475(%rip), %rsi      # 0x7fc0
callq 0x2160
jmp 0x2b52
movq -0x47adb8(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x47adb8(%rbp)
jmp 0x270f
movq 0x5460(%rip), %rdi      # 0x7fd0
movq 0x5449(%rip), %rsi      # 0x7fc0
callq 0x2160
movq 0x544d(%rip), %rdi      # 0x7fd0
leaq 0x251a(%rip), %rsi      # 0x50a4
callq 0x2150
movq %rax, %rdi
movsd -0x18(%rbp), %xmm0
movsd 0x2481(%rip), %xmm1     # 0x5020
divsd %xmm1, %xmm0
callq 0x22a0
movq %rax, %rdi
leaq 0x2518(%rip), %rsi      # 0x50ca
callq 0x2150
movq %rax, %rdi
movq 0x53ff(%rip), %rsi      # 0x7fc0
callq 0x2160
movq 0x5403(%rip), %rdi      # 0x7fd0
leaq 0x24fa(%rip), %rsi      # 0x50ce
callq 0x2150
movq %rax, %rdi
movsd -0x20(%rbp), %xmm0
movsd 0x2437(%rip), %xmm1     # 0x5020
divsd %xmm1, %xmm0
callq 0x22a0
movq %rax, %rdi
leaq 0x24ce(%rip), %rsi      # 0x50ca
callq 0x2150
movq %rax, %rdi
movq 0x53b5(%rip), %rsi      # 0x7fc0
callq 0x2160
cmpq $0x0, -0x10(%rbp)
jne 0x2c39
movq 0x53b2(%rip), %rdi      # 0x7fd0
leaq 0x24c6(%rip), %rsi      # 0x50eb
callq 0x2150
movq %rax, %rdi
movq 0x538c(%rip), %rsi      # 0x7fc0
callq 0x2160
movq 0x5390(%rip), %rdi      # 0x7fd0
leaq 0x24b6(%rip), %rsi      # 0x50fd
callq 0x2150
movq %rax, %rdi
movsd -0x28(%rbp), %xmm0
movsd 0x23c4(%rip), %xmm1     # 0x5020
divsd %xmm1, %xmm0
callq 0x22a0
movq %rax, %rdi
leaq 0x245b(%rip), %rsi      # 0x50ca
callq 0x2150
movq %rax, %rdi
movq 0x5342(%rip), %rsi      # 0x7fc0
callq 0x2160
movq 0x5346(%rip), %rdi      # 0x7fd0
leaq 0x248c(%rip), %rsi      # 0x511d
callq 0x2150
movq %rax, %rdi
movsd -0x30(%rbp), %xmm0
movsd 0x237a(%rip), %xmm1     # 0x5020
divsd %xmm1, %xmm0
callq 0x22a0
movq %rax, %rdi
leaq 0x2486(%rip), %rsi      # 0x513f
callq 0x2150
movq %rax, %rdi
movq 0x52f8(%rip), %rsi      # 0x7fc0
callq 0x2160
movq 0x52fc(%rip), %rdi      # 0x7fd0
leaq 0x2468(%rip), %rsi      # 0x5143
callq 0x2150
movq %rax, %rdi
cvtsi2sdq -0x10(%rbp), %xmm1
movsd 0x232f(%rip), %xmm0     # 0x5020
mulsd %xmm1, %xmm0
movsd 0x2323(%rip), %xmm1     # 0x5020
divsd %xmm1, %xmm0
callq 0x22a0
movq %rax, %rdi
leaq 0x2442(%rip), %rsi      # 0x5152
callq 0x2150
movq %rax, %rdi
movq 0x52a1(%rip), %rsi      # 0x7fc0
callq 0x2160
movq -0x58(%rbp), %rax
movq %rax, -0x47ae60(%rbp)
cmpq $0x0, %rax
je 0x2d41
movq -0x47ae60(%rbp), %rdi
callq 0x21d0
movq -0x50(%rbp), %rax
movq %rax, -0x47ae68(%rbp)
cmpq $0x0, %rax
je 0x2d5e
movq -0x47ae68(%rbp), %rdi
callq 0x21d0
movq 0x526b(%rip), %rdi      # 0x7fd0
leaq 0x23e8(%rip), %rsi      # 0x5154
callq 0x2150
movq %rax, %rdi
movq 0x5245(%rip), %rsi      # 0x7fc0
callq 0x2160
movq 0x5259(%rip), %rdi      # 0x7fe0
callq 0x2280
xorl %eax, %eax
addq $0x47ae70, %rsp         # imm = 0x47AE70
popq %rbp
retq
nopw (%rax,%rax)