/* $Id: t_bdRSA_blinded.c $ */

/* Carry out RSA calculations using constant-time exponentiation and blinding */

/***** BEGIN LICENSE BLOCK *****
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2001-16 David Ireland, D.I. Management Services Pty Limited
 * <http://www.di-mgt.com.au/bigdigits.html>. All rights reserved.
 *
 ***** END LICENSE BLOCK *****/
/*
 * Last updated:
 * $Date: 2016-03-31 09:51:00 $
 * $Revision: 2.6.1 $
 * $Author: dai $
 */


#if _MSC_VER >= 1100
	/* Detect memory leaks in MSVC++ */ 
	#define _CRTDBG_MAP_ALLOC
	#include <stdlib.h>
	#include <crtdbg.h>
#else
	#include <stdlib.h>
#endif

#include <stdio.h>
#include <time.h>
#include <assert.h>
#include "bigd.h"
#include "bigdRand.h"


int main(void)
{
	size_t nbits;
	BIGD N, e, d;
	BIGD m, c, r, g, R, S, x, z, y;
	int isequal;
	size_t i;
	clock_t start, finish;
	double tinv, tinv_ct, tblind;
	int b;
	const size_t ntimes = 3;

/* MSVC memory leak checking stuff */
#if _MSC_VER >= 1100
	_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
	_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
	_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
	_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
	_CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );
	_CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
	_CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );
#endif

	printf("Carry out RSA calculation using constant-time exponentiation and blinding.\n");

	/* Initialise */
	bdNewVars(&N, &e, &d, &m, &c, &y, &r, &g, &R, &S, &x, &z);

	/* Read in public and private keys as BIGDs */
	/*
	Source: Alice's 1024-bit RSA key from [RFC4134]:
	Hoffman, P., Ed., "Examples of S/MIME Messages", RFC 4134, July 2005.
	*/

	bdConvFromHex(N, "E08973398DD8F5F5E88776397F4EB005BB5383DE0FB7ABDC7DC775290D052E6D12DFA68626D4D26FAA5829FC97ECFA82510F3080BEB1509E4644F12CBBD832CFC6686F07D9B060ACBEEE34096A13F5F7050593DF5EBA3556D961FF197FC981E6F86CEA874070EFAC6D2C749F2DFA553AB9997702A648528C4EF357385774575F");
	bdConvFromHex(e, "010001");
	bdConvFromHex(d, "A403C327477634346CA686B57949014B2E8AD2C862B2C7D748096A8B91F736F275D6E8CD15906027314735644D95CD6763CEB49F56AC2F376E1CEE0EBF282DF439906F34D86E085BD5656AD841F313D72D395EFE33CBFF29E4030B3D05A28FB7F18EA27637B07957D32F2BDE8706227D04665EC91BAF8B1AC3EC9144AB7F21");

	printf("Public key:\n");
	bdPrintHex("N=", N, "\n");
	bdPrintHex("e=", e, "\n");
	printf("Private key:\n");
	bdPrintHex("d=", d, "\n");

	nbits = bdBitLength(N);
	printf("Key size = %d bits\n", nbits);

	/* Set a random message m < N */
	bdQuickRandBits(m, nbits-8);
	bdPrintHex("Random plaintext m =\n", m, "\n");

	/* Encrypt c = m^e mod N */
	/* NB no need to use constant-time modexp when using public exponent */
	bdModExp(c, m, e, N);
	bdPrintHex("Ciphertext c=m^e mod N=\n", c, "\n");

	printf("\nSIMPLE DECRYPTION USING PRIVATE EXPONENT...\n");
	/* Check decrypt m1 = c^d mod N */
	start = clock();
	/* Use standard non-constant-time modexp with private exponent 
		=> faster but vulnerable to simple power attack (SPA) */
	bdModExp(y, c, d, N);
	finish = clock();
	tinv = (double)(finish - start) / CLOCKS_PER_SEC;
	bdPrintHex("y=c^d mod N (standard)\n", y, "\n");
	isequal = bdCompare_ct(y, m);
	printf("Decryption %s\n", (isequal == 0 ? "OK" : "FAILED!"));
	assert(isequal == 0);
	printf("Decryption by standard modexp took %.3f secs\n", tinv);

	/* Now decrypt using constant-time modexp */
	start = clock();
	/* Resistant to simple power attack, but not differential power analysis (DPA) */
	bdModExp_ct(y, c, d, N);
	finish = clock();
	tinv_ct = (double)(finish - start) / CLOCKS_PER_SEC;
	bdPrintHex("y=c^d mod N (constant-time)\n", y, "\n");
	isequal = bdCompare_ct(y, m);
	printf("Decryption %s\n", (isequal == 0 ? "OK" : "FAILED!"));
	assert(isequal == 0);
	printf("Decryption by constant-time modexp took %.3f secs\n", tinv_ct);
	printf("Ratio constant-time/standard = %.3f\n", tinv_ct / tinv);

	/*
	USE BLINDING TO DEFEAT DPA
	Differential power analysis depends on the attacker knowing the base c of the exponentiation.
	This can succeed even if constant-time exponentiation is used.
	Ref: Jean-Sebastian Coron, "Resistance Against Differential Power Analysis for 
	Elliptic Curve Cryptosystems", August 1999.
	   -- This version adapted from Coron's elliptic curve point scalar multiplication 
	   to RSA-style modular exponentiation.
	*/

	/* Algorithm: Modular exponentiation with blinding.
	Input: RSA ciphertext c, private exponent d, public exponent e, modulus N
	Output: RSA plaintext c^d mod N
	1. Select a random integer r < N with gcd(r,N) = 1
	2. Compute R = r^e mod N and S = r^-1 mod N
	3. Compute x = c.R mod N
	4. Compute z = x^d mod N
	5. Compute y = S.z mod N
	6. Return y
	*/

	/* 
	You could store the values R and S initially and refresh on each execution by
	    R <-- R^{2(-1)^b}
		S <-- S^{2(-1)^b}
	where b is a random bit generated at each new execution.
	*/

	printf("\nUSING BLINDING...\n");
	start = clock();
	printf("1. Select a random integer r < N with gcd(r,N) = 1 \n");
	do {
		bdRandomBits(r, nbits);
		bdModulo(r, r, N);
		bdGcd(g, r, N);
	} while (bdShortCmp(g, 1) != 0);
	bdPrintHex("r=", r, "\n");
	bdPrintHex("[CHECK] gcd(r,n)=", g, "\n");

	printf("2. Compute R = r^e mod N and S = r^-1 mod N \n");
	bdModExp(R, r, e, N);	/* NB public exponent, so no need for CT */
	bdModInv(S, r, N);
	bdPrintHex("R=r^e mod N=", R, "\n");
	bdPrintHex("S=r^-1 mod N=", S, "\n");

	printf("3. Compute x = c.R mod N \n");
	bdModMult(x, c, R, N);
	bdPrintHex("x = c.R mod N=", x, "\n");

	printf("4. Compute z = x^d mod N \n");
	bdModExp_ct(z, x, d, N);
	bdPrintHex("z = b^d mod N=", z, "\n");

	printf("5. Compute y = S.z mod N \n");
	bdModMult(y, S, z, N);
	bdPrintHex("y = S.z mod N=", y, "\n");

	finish = clock();	/* Assume effect of printing is negligible (?) */
	tblind = (double)(finish - start) / CLOCKS_PER_SEC;

	printf("6. Return y = c^d mod N \n");

	isequal = bdCompare_ct(y, m);
	printf("Decryption %s\n", (isequal == 0 ? "OK" : "FAILED!"));
	assert(isequal == 0);
	printf("Decryption using blinding took %.3f secs\n", tblind);
	printf("Ratio blinding/standard (with printing) = %.3f\n", tblind / tinv);

	printf("\nREPEAT WITH REFRESHED R AND S...\n");
	tblind = 0;

	for (i = 0; i < ntimes; i++) {
		printf("Iteration number %d:\n", i+1);

		/* Generate a random bit */
		b = bdRandDigit() & 0x1;
		printf("Random bit b=%d\n", b);

		start = clock();
		/* R <-- R^{2(-1)^b}, S <-- S^{2(-1)^b} */
		bdModMult(R, R, R, N);
		bdModMult(S, S, S, N);
		if (b) {
			bdModInv(R, R, N);
			bdModInv(S, S, N);
		}

		/* 3. Compute x = c.R mod N */
		bdModMult(x, c, R, N);

		/* 4. Compute z = x^d mod N */
		bdModExp_ct(z, x, d, N);

		/* 5. Compute y = S.z mod N */
		bdModMult(y, S, z, N);

		finish = clock();
		tblind += (double)(finish - start) / CLOCKS_PER_SEC;

		bdPrintHex("R <-- R^{2(-1)^b}=\n", R, "\n");
		bdPrintHex("S <-- S^{2(-1)^b}=\n", S, "\n");

		/* 6. Return y = c^d mod N */
		bdPrintHex("Output y=\n", y, "\n");

		isequal = bdCompare_ct(y, m);
		printf("Decryption %s\n", (isequal == 0 ? "OK" : "FAILED!"));
		assert(isequal == 0);

		printf("\n");
	}

	tblind /= ntimes;
	printf("Decryption using blinding took on average %.3f secs over %d repeats\n", tblind, ntimes);
	printf("Ratio blinding/standard = %.3f\n", tblind / tinv);


	/* Clean up */
	bdFreeVars(&N, &e, &d, &m, &c, &y, &r, &g, &R, &S, &x, &z);

	printf("\nOK, SUCCESSFULLY COMPLETED TESTS WITHOUT ERROR.\n");

	return 0;
}
