
#pragma attribute("aid", "f0000001") // CJT - The AID has to match the AID in tag 4F in the dir attribute
#pragma attribute("dir", "61 10 4f 4 f0 00 00 01 50 8 65 6c 6f 79 61 6c 74 79")
// CJT Alternatively, with the latest compiler v3.1.0.4 you can use the following line instead of the dir attribute
// This will correctly calculate the dir attribute from the aid and name attributes
// #pragma attribute("name","my application")

// CJT You can add this pragma to ensure that the correct permissions are given to the application when loaded via hterm
// Without the card could abend when calling crypto functions
// #pragma attribute("access_list", "0007") // Contact + Contactless + Strong Crypto

#include <string.h>
#include <ISO7816.h>
#include <multoscomms.h>
#include <multoscrypto.h>
#include <multosarith.h>
#include <multosccr.h> // for ZFlag()

#define APDU_DATA_LENGTH_MAX       			256

#define CURVE_SIZE       					24
#define CURVE_POINT_SIZE       				49		// 1 + 2*CURVE_SIZE
#define HASH_SHA1_SIZE     					20
#define RANDOM_NUMBER_BLOCK					8
#define OFFSET_EC_DomainParams_N 			122 	// 2 + 5*CURVE_SIZE
#define OFFSET_ZERO_BYTE					1


/****************************************/
/* 			Response codes		 		*/
/****************************************/
#define ERR_OK          					0x9000
#define ERR_WRONGCLASS  					0x6402
#define ERR_BAD_INS     					0x6404
#define ERR_CHECK_CASE    					0x6405
#define ERR_TOO_MANY_PREV_VERIF   			0x6406


/****************************************/
/* 			MULTOS codes		 		*/
/****************************************/
#define __PRIM_ECC_SCALAR_MULTIPLICATION	0xD4
#define __PRIM_ECC_ADDITION                 0xD0
#define __PRIM_MODULAR_REDUCTION            0xC3
#define __PRIM_RANDOM_NUMBER				0xc4
#define __PRIM_COPY_NON_ATOMIC 				0x0F


/*******************************************/
/* 			Commands codes		 		   */
/*******************************************/
#define CLA_BUT_AAS      	0x80

#define INS_INIT       		0x01
#define INS_SETSIG0       	0x02
#define INS_SETSIGXI       	0x03
#define INS_GETREVPROOF1    0x04

#define INS_INITVERIF       0x10
#define INS_GETPROOF1      	0x05
#define INS_GETPROOF2      	0x12
#define INS_GETPROOF3      	0x06
#define INS_GETPROOF4      	0x07
#define INS_GETREVPROOF2    0x11 // todo: change the numbering, sort, make sense of it

#define INS_SETLS           0x08
#define INS_SETALPHAS       0x09

#define INS_GETPREVVERIF    0x35

#define INS_GETSIG0			0x32	// Test
#define INS_GETSIGXI		0x33	// Test
#define INS_GETRND			0x34	// Test

#define INS_GETR            0x36	// Test
#define INS_GETC            0x37    // Test
#define INS_GETTREVOKE      0x38    // Test
#define INS_GETSFORREV      0x39    // Test
#define INS_CHECKPREVVERIF  0x40	// Test
#define INS_REVOCATIONPTCL  0x42	// Test

#define P2_SETSIGXI_PART1  	0x01
#define P2_SETSIGXI_PART2  	0x02

#define P2_GETRND_PART1  	0x01	// Test
#define P2_GETRND_PART2  	0x02	// Test


typedef unsigned char BYTE;


/*******************************************/
/* 			Structures definition		   */
/*******************************************/
typedef struct{
	BYTE x;	// 1
	BYTE ecc_multiplier[CURVE_SIZE];	//24
} ECC_multiplier;	// 1 + 24 = 25



typedef struct{
	ECC_multiplier v;		// 25
	ECC_multiplier rhov;	// 25
	ECC_multiplier rhor;	// 25
	ECC_multiplier rhomR;	// 25
	ECC_multiplier rhom1;	// 25
	ECC_multiplier rhom2;	// 25
	ECC_multiplier rhom3;	// 25
	ECC_multiplier rhom4;	// 25
	ECC_multiplier rhom5;	// 25
	ECC_multiplier rhom6;	// 25
	ECC_multiplier rhom7;	// 25
	ECC_multiplier rhom8;	// 25
	ECC_multiplier rhom9;	// 25
} RNDNumbers; // 13 * 25 = 325


typedef struct{
	BYTE attRev[CURVE_SIZE];
	BYTE att1[CURVE_SIZE];
	BYTE att2[CURVE_SIZE];
	BYTE att3[CURVE_SIZE];
	BYTE att4[CURVE_SIZE];
	BYTE att5[CURVE_SIZE];
	BYTE att6[CURVE_SIZE];
	BYTE att7[CURVE_SIZE];
	BYTE att8[CURVE_SIZE];
	BYTE att9[CURVE_SIZE];
} setOfAttributes;

typedef struct{
	BYTE form;		// 1
	BYTE x[CURVE_SIZE];	//24
	BYTE y[CURVE_SIZE];	//24
} ECPoint;	// 49


typedef struct{
	ECPoint sigRev;
	ECPoint sig1;
	ECPoint sig2;
	ECPoint sig3;
	ECPoint sig4;
	ECPoint sig5;
	ECPoint sig6;
	ECPoint sig7;
	ECPoint sig8;
	ECPoint sig9;
} setOfSignatures;

//added stuff REVOCATION PROTOCOL
typedef struct{
	BYTE alpha1[CURVE_SIZE];
	BYTE alpha2[CURVE_SIZE];
} setOfAlphas; // 48

typedef struct{
	BYTE l1[CURVE_SIZE];
	BYTE l2[CURVE_SIZE];
	BYTE l3[CURVE_SIZE];
	BYTE l4[CURVE_SIZE];
	BYTE l5[CURVE_SIZE];
	BYTE l6[CURVE_SIZE];
	BYTE l7[CURVE_SIZE];
	BYTE l8[CURVE_SIZE];
	BYTE l9[CURVE_SIZE];
	BYTE l10[CURVE_SIZE];
} setOfLs;
//REVOCATION PROTOCOL stuff ended


/*************************************************************************************************************/
/* 										Global values		 RAM (Public memory)		     	       		 */
/*************************************************************************************************************/
#pragma melpublic
BYTE apdu_data[APDU_DATA_LENGTH_MAX];


/************************************************************************************************************/
/* 										Session values		RAM (Dynamic memory)							*/
/************************************************************************************************************/
#pragma melsession	// TOTAL 472 B
BYTE i;	// 1
BYTE z[2*CURVE_SIZE]; // 48

ECPoint tempPoint; // 49
ECPoint t_verify; //49

BYTE numProveAtt; // 1

// Revocation protocol RAM values
ECC_multiplier tmp;	// 25
ECPoint t_revoke;
BYTE numPrevVerificationsCAST[CURVE_SIZE]; // TODO: delete this value, contains just one BYTE, serves for check

RNDNumbers rndNumbers; 	// 325	//Project have to be build with SmartDeck, if you debug project with SmartDeck,
								//SmartDeck will crash, maybe there is not enough RAM memory,
								//in case that it is necessary to debug project, move "RNDNumbers rndNumbers;" to static memory!


/************************************************************************************************************/
/* 										Static values		EEPROM (Static memory)							*/
/************************************************************************************************************/
#pragma melstatic

BYTE numAttributes; // number including attribute m_R
setOfAttributes attributes;
setOfSignatures signatures;
ECPoint sigma;
//RNDNumbers rndNumbers;
BYTE e[CURVE_SIZE]; // 24

//static values for REVOCATION PROTOCOL

BYTE numOfLs;
BYTE numOfAlphas;
setOfAlphas alphas;
setOfLs ls;

BYTE nonce[CURVE_SIZE];
BYTE epochHash[CURVE_SIZE];
BYTE numPrevVerifications;

BYTE rho_mR[CURVE_SIZE];
BYTE r[CURVE_SIZE];
BYTE smr[CURVE_SIZE];
BYTE sr[CURVE_SIZE];
ECPoint c;

//REVOCATION PROTOCOL static values ended

BYTE ecDomainParams[] = {
0x00, // Format of domain params
0x18, // Prime length in bytes
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 	// P
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC,  	// A
0x64, 0x21, 0x05, 0x19, 0xE5, 0x9C, 0x80, 0xE7, 0x0F, 0xA7, 0xE9, 0xAB,
0x72, 0x24, 0x30, 0x49, 0xFE, 0xB8, 0xDE, 0xEC, 0xC1, 0x46, 0xB9, 0xB1,		// B
0x18, 0x8D, 0xA8, 0x0E, 0xB0, 0x30, 0x90, 0xF6, 0x7C, 0xBF, 0x20, 0xEB,
0x43, 0xA1, 0x88, 0x00, 0xF4, 0xFF, 0x0A, 0xFD, 0x82, 0xFF, 0x10, 0x12, 	// Gx
0x07, 0x19, 0x2B, 0x95, 0xFF, 0xC8, 0xDA, 0x78, 0x63, 0x10, 0x11, 0xED,
0x6B, 0x24, 0xCD, 0xD5, 0x73, 0xF9, 0x77, 0xA1, 0x1E, 0x79, 0x48, 0x11, 	// Gy
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x99, 0xDE, 0xF8, 0x36, 0x14, 0x6B, 0xC9, 0xB1, 0xB4, 0xD2, 0x28, 0x31,  	// N
0x01 // H
};

BYTE pointG[] = {0x04,																		// form
				 0x18, 0x8D, 0xA8, 0x0E, 0xB0, 0x30, 0x90, 0xF6, 0x7C, 0xBF, 0x20, 0xEB,
				 0x43, 0xA1, 0x88, 0x00, 0xF4, 0xFF, 0x0A, 0xFD, 0x82, 0xFF, 0x10, 0x12, 	// Gx
				 0x07, 0x19, 0x2B, 0x95, 0xFF, 0xC8, 0xDA, 0x78, 0x63, 0x10, 0x11, 0xED,
				 0x6B, 0x24, 0xCD, 0xD5, 0x73, 0xF9, 0x77, 0xA1, 0x1E, 0x79, 0x48, 0x11}; 	// Gy

BYTE modOrder[] ={0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
				  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
				  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
				  0x99, 0xDE, 0xF8, 0x36, 0x14, 0x6B, 0xC9, 0xB1, 0xB4, 0xD2, 0x28, 0x31}; 	// N


/*******************************************/
/* 			Function definitions		   */
/*******************************************/

void generateAttributes(BYTE *buffer, BYTE number);

void getRandom_v(void);
void getRandom_rho_v(void);
void getRandom_rho_mi(BYTE *buffer, BYTE numProveAtt);

void comSigmaXi(BYTE *buffer_rndNumbers, BYTE *buffer_signatures);
void comProofTVerify(BYTE numProveAtt);

void comProofSv(void);
void comProofSmi(BYTE *buffer_attribute, BYTE *buffer_rndNumbers, BYTE *buffer_apdu);

// FOR REVOCATION:
void getRandom_rho_r(void);

void compute_r(BYTE *buffer_firstL, BYTE *buffer_secondL);
void compute_c(void);

void comProofTRevoke(void);

void comProofSmr(void);
void comProofSr(void);




/*******************************************/
/* 			APDU processing 	 		   */
/*******************************************/
void main(void)
{
	// Check class in APDU
	if (CLA != CLA_BUT_AAS){
		ExitSW(ERR_WRONGCLASS);
	}


	// Check instance value in the APDU command
	switch(INS){

 //***********************************************************//
 //				ISSUE ATTRIBUTES PROTOCOL				   	  //
 //***********************************************************//

	case INS_INIT:

		if (!CheckCase(2))
			ExitSW(ERR_CHECK_CASE);

		memcpy((BYTE*) &numAttributes, (BYTE*) &P1, sizeof(BYTE));
  		generateAttributes((BYTE*)&attributes.attRev, numAttributes);

  		memcpy(apdu_data, (BYTE*) &attributes, P1*CURVE_SIZE);
  		ExitLa(Le);
  		break;

  	 case INS_SETSIG0:

  		 if (!CheckCase(3))
  			 ExitSW(ERR_CHECK_CASE);

  		 memcpy((BYTE*) &sigma, apdu_data, (1+2*CURVE_SIZE));

  		 ExitSW(ERR_OK);
  		 break;

  	 case INS_GETSIG0:	// Test

  		 if (!CheckCase(2))
  			 ExitSW(ERR_CHECK_CASE);

  		 memcpy(apdu_data, (BYTE*) &sigma, (1+2*CURVE_SIZE));

  		 ExitLa(Le);
  		 break;

  	 case INS_SETSIGXI:

  		 if (!CheckCase(3))
  			 ExitSW(ERR_CHECK_CASE);

  		 if(P2 == P2_SETSIGXI_PART1)
  			 memcpy((BYTE*)&signatures.sigRev, apdu_data, Lc);

  		 if(P2 == P2_SETSIGXI_PART2)
  			 memcpy((BYTE*)&signatures.sig6, apdu_data, Lc);

  		 ExitSW(ERR_OK);
  		 break;

  	  case INS_GETSIGXI:

  		 if (!CheckCase(2))
  			 ExitSW(ERR_CHECK_CASE);

  		 if(P2 == P2_SETSIGXI_PART1)
  			 memcpy(apdu_data, (BYTE*)&signatures.sigRev, Le);

  		 if(P2 == P2_SETSIGXI_PART2)
  			 memcpy(apdu_data, (BYTE*)&signatures.sig6, Le);

  		 ExitLa(Le);
  		 break;

 //***********************************************************//
 //				ISSUE REVOCATION PROTOCOL				   	  //
 //***********************************************************//

  	  case INS_SETLS:
   		 if (!CheckCase(2))
   			 ExitSW(ERR_CHECK_CASE);

 		memcpy((BYTE*) &numOfLs, (BYTE*) &P1, sizeof(BYTE)); // issuer sends APDUComm with P1 = numOfLs
   		generateAttributes((BYTE*)&ls.l1, numOfLs);

   		memcpy(apdu_data, (BYTE*) &ls, P1*CURVE_SIZE);
   		ExitLa(Le);
   		break;

  	  case INS_SETALPHAS:
   		 if (!CheckCase(2))
   			 ExitSW(ERR_CHECK_CASE);

 		memcpy((BYTE*) &numOfAlphas, (BYTE*) &P1, sizeof(BYTE)); // issuer sends APDUComm with P1 = numOfAlphas
   		generateAttributes((BYTE*)&alphas.alpha1, numOfAlphas);

   		memcpy(apdu_data, (BYTE*) &alphas, P1*CURVE_SIZE);
   		ExitLa(Le);
   		break;
  		  
//***********************************************************//
//					  REVOCATION PROTOCOL		    	     //
//***********************************************************//

 	  case INS_GETPREVVERIF:
  		 if (!CheckCase(3))
  			 ExitSW(ERR_CHECK_CASE);

 	   	 if (numPrevVerifications > 99)
 	   		 ExitSW(ERR_TOO_MANY_PREV_VERIF);

 	   	 // SETTING THE EPOCH AND NUM PREV REVOCATION

 	   	 // temporal storing of epoch to RAM element
 	   	 __code(PUSHZ, CURVE_SIZE-HASH_SHA1_SIZE);
 	   	 __push(BLOCKCAST(HASH_SHA1_SIZE) apdu_data);
 	   	 __code(STORE, tmp.ecc_multiplier, CURVE_SIZE);

   		 // same epoch
   		 if (memcmp(epochHash, tmp.ecc_multiplier, CURVE_SIZE) == 0){
   			numPrevVerifications = numPrevVerifications+1;
   		 }

   		 // null numPrevVerifications for new epoch
   		 else {
			memcpy((BYTE*)&epochHash, (BYTE*)&tmp.ecc_multiplier, CURVE_SIZE);
			numPrevVerifications = 0;
   		 }

  		 ExitSW(ERR_OK);
  		 break;

	 // computes c
	 // computes t_revoke
	 // return c, t_revoke, c_exponent, rhomR, rho_r
  	  case INS_GETREVPROOF1:
   		 if (!CheckCase(2))
   			 ExitSW(ERR_CHECK_CASE);

 	   	 if (numPrevVerifications > 99)
 	   		 ExitSW(ERR_TOO_MANY_PREV_VERIF);

   		 //COMPUTING C AND T_REVOKE AND SENDING TO THE TERMINAL
		 compute_c(); // computes c and stores it in c
		 memcpy(apdu_data, (BYTE*)&c, CURVE_POINT_SIZE);

		 getRandom_rho_r();
		 // has to have rho_mR computed already

		 comProofTRevoke(); // computes t_revoke and stores it as a second element in apdu_data

 		 memcpy(apdu_data+2*CURVE_POINT_SIZE, (BYTE*)&rndNumbers.rhor.ecc_multiplier, CURVE_SIZE);
 		 memcpy(apdu_data+2*CURVE_POINT_SIZE+CURVE_SIZE, (BYTE*)&rndNumbers.rhomR.ecc_multiplier, CURVE_SIZE);
 		 memcpy(apdu_data+2*CURVE_POINT_SIZE+2*CURVE_SIZE, (BYTE*)&rndNumbers.rhor.ecc_multiplier, CURVE_SIZE);

   		 ExitLa(Le);
   		 break;

   	// computes s_mR, s_r
   	// sends back attRev, e, r
  	  case INS_GETREVPROOF2:
   		 if (!CheckCase(2))
   			 ExitSW(ERR_CHECK_CASE);

 		 comProofSr();
 		 memcpy(apdu_data, (BYTE*)&sr, CURVE_SIZE);

 		 comProofSmr();
 		 memcpy(apdu_data+CURVE_SIZE, (BYTE*)&smr, CURVE_SIZE);

 		 memcpy(apdu_data+2*CURVE_SIZE, (BYTE*)&attributes.attRev, CURVE_SIZE);
 		 memcpy(apdu_data+3*CURVE_SIZE, (BYTE*)&e, CURVE_SIZE);
 		 memcpy(apdu_data+4*CURVE_SIZE, (BYTE*)&r, CURVE_SIZE);

   	     ExitLa(Le);
   		 break;


//***********************************************************//
//					PROVE ATTRIBUTES PROTOCOL			     //
//***********************************************************//

   	// checks epochHash and stores new if necessary
   	// store nonce value
 	  case INS_INITVERIF:
  		 if (!CheckCase(3))
  			 ExitSW(ERR_CHECK_CASE);

  		 // todo: get nonce
 	   	 if (numPrevVerifications > 99)
 	   		 ExitSW(ERR_TOO_MANY_PREV_VERIF);

 	   	 // SETTING THE EPOCH AND NUM PREV REVOCATION
 	   	 // temporal storing of epoch to nonce, which has not been set to real nonce yet
 	   	 __code(PUSHZ, CURVE_SIZE-HASH_SHA1_SIZE);
 	   	 __push(BLOCKCAST(HASH_SHA1_SIZE) apdu_data);
 	   	 __code(STORE, nonce, CURVE_SIZE); // temporal storing of epoch in nonce

   		 // same epoch
   		 if (memcmp(epochHash, nonce, CURVE_SIZE) == 0){
   			numPrevVerifications = numPrevVerifications+1;
   		 }

   		 // null numPrevVerifications for new epoch
   		 else {
			memcpy((BYTE*)&epochHash, (BYTE*)&nonce, CURVE_SIZE);
			numPrevVerifications = 0;
   		 }

   		 // store nonce from apdu_data
   		 memcpy((BYTE*)&nonce, apdu_data+HASH_SHA1_SIZE, CURVE_SIZE);

  		 ExitSW(ERR_OK);
  		 break;

  	// computes random values for proof, v,rho_v,rho_mi,rho_r
  	// computes c, t_revoke for revocation
    // computes t_verify, randomized sigma
  	// send back t_revoke, c, e, sv
  	// computes sr and smr and stores the values in eeprom
  	  case INS_GETPROOF1:

  		 if (!CheckCase(2))
  			 ExitSW(ERR_CHECK_CASE);

  		 memcpy((BYTE*)&numProveAtt, (BYTE*)&P1, sizeof(BYTE));

  		 //compute random numbers (store to the session memory (Dynamic RAM))
  		 getRandom_v();
  		 getRandom_rho_v();
  		 getRandom_rho_mi((BYTE*)&rndNumbers.rhomR, P1); // rhomR is already computed by GETREVPROOF1

  		 getRandom_rho_r();

   		compute_c(); // and stores it in c
   		comProofTRevoke(); // and stores in t_revoke

  		//compute point t_verify (store to the global memory (Public RAM)) addr: apdu_data
  		comProofTVerify(P1);													// 	apdu_data: pi.t_verify			(stack:   49 bytes)

  		//compute sigma with roof (store to the global memory (Public RAM)) addr: apdu_data: pi.t_verify||sigmaRND
  		__push (ecDomainParams);
  		__push ((BYTE*)&sigma);
  		__push ((BYTE*)&rndNumbers.v);
  		__push (apdu_data+CURVE_POINT_SIZE);
  		__code (PRIM, __PRIM_ECC_SCALAR_MULTIPLICATION); // 	apdu_data: pi.t_verify||sigmaRND			(stack:   98 bytes)

  		memcpy(apdu_data+2*CURVE_POINT_SIZE, (BYTE*)&t_revoke, CURVE_POINT_SIZE);
  		memcpy(apdu_data+3*CURVE_POINT_SIZE, (BYTE*)&c, CURVE_POINT_SIZE);
  		memcpy(apdu_data+4*CURVE_POINT_SIZE, (BYTE*)&nonce, CURVE_SIZE); // adding nonce to the hash, will not be sent back: overwritten by computed e
  		
  		//compute hash SHA1(pi.t||sigmaRND||t_revoke||c||nonce)
  		SHA1(4*CURVE_POINT_SIZE+CURVE_SIZE, e+(CURVE_SIZE-HASH_SHA1_SIZE), apdu_data); //  SHA1(size, output, input)
  		memcpy(apdu_data+4*CURVE_POINT_SIZE, e, CURVE_SIZE);		        // 	apdu_data: pi.t_verify||sigmaRND||pi.e 	(stack:   122 bytes)
  		comProofSv();													    // 	apdu_data: pi.t_verify||sigmaRND||pi.e||sv (stack:   146 bytes)
  		comProofSr(); // stored in sr, store in apdu as first CURVE_SIZE
  		comProofSmr(); // stored in smr, store in apdu as second CURVE_SIZE

  		/* 	WOULD CAUSE OUT OF BOUND EXCEPTION, TOO LONG
		comProofSr(); // stored in nonce, store in apdu as first CURVE_SIZE
		memcpy(apdu_data+4*CURVE_POINT_SIZE+CURVE_SIZE, (BYTE*)&sr, CURVE_SIZE);

		comProofSmr(); // stored in nonce, store in apdu as second CURVE_SIZE
		memcpy(apdu_data+4*CURVE_POINT_SIZE+2*CURVE_SIZE, (BYTE*)&smr, CURVE_SIZE);
  		*/

  		ExitLa(Le);
  		break;

  	// sends to terminal values sr and smr
  	// they must be computed beforehand
  	  case INS_GETPROOF2:

  		if (!CheckCase(2))
  			 ExitSW(ERR_CHECK_CASE);

		memcpy(apdu_data, (BYTE*)&sr, CURVE_SIZE);
		memcpy(apdu_data+CURVE_SIZE, (BYTE*)&smr, CURVE_SIZE);

   		ExitLa(Le);
   		break;


  	 case INS_GETRND:	// Test
  		 
  		if (!CheckCase(2))
  			ExitSW(ERR_CHECK_CASE);

  		if(P2 == P2_GETRND_PART1){
  			memcpy(apdu_data, rndNumbers.v.ecc_multiplier, CURVE_SIZE);
  			memcpy(apdu_data+CURVE_SIZE, rndNumbers.rhov.ecc_multiplier , CURVE_SIZE);
  		}

  		if(P2 == P2_GETRND_PART2){
  			for(i=0;i<10; i++)
  				memcpy(apdu_data+i*CURVE_SIZE, (BYTE*)&rndNumbers.rhomR.ecc_multiplier + i*(1+CURVE_SIZE), CURVE_SIZE);
  		}


  		ExitLa(Le);
  		break;

  	 case INS_GETPROOF3:
  		 
  		if (!CheckCase(2))
  			ExitSW(ERR_CHECK_CASE);

  		for(i=numProveAtt;i<numAttributes; i++)
  			memcpy(apdu_data+(i-numProveAtt)*CURVE_SIZE, attributes.attRev + i*CURVE_SIZE, CURVE_SIZE);

  		ExitLa(Le);
  		break;

  	 case INS_GETPROOF4:

  		 if (!CheckCase(2))
  			ExitSW(ERR_CHECK_CASE);

  		 comProofSmi((BYTE*)&attributes.attRev, (BYTE*)&rndNumbers.rhomR, apdu_data);

  		for(i=numProveAtt;i<numAttributes; i++)
  			memcpy(apdu_data+numProveAtt*CURVE_SIZE+(i-numProveAtt)*CURVE_SIZE, attributes.attRev + i*CURVE_SIZE, CURVE_SIZE);

  		ExitLa(Le);
  		break;

//***********************************************************//
//					CHECK REVOCATION PROTOCOL			     //
//***********************************************************//

  	// sends back number of previous verifications
    // does not compute, must be computed beforehand
 	   case INS_CHECKPREVVERIF:
 	   	 if (!CheckCase(2))
 	   		 ExitSW(ERR_CHECK_CASE);

  		 numPrevVerificationsCAST[CURVE_SIZE-1] = numPrevVerifications; // add as the last character
  		 numPrevVerificationsCAST[CURVE_SIZE] = '\0'; // add a new null terminator

  		 memcpy(apdu_data, (BYTE*)&numPrevVerificationsCAST, CURVE_SIZE);
  		 memcpy(apdu_data+CURVE_SIZE, (BYTE*)&epochHash, CURVE_SIZE);

  		 ExitLa(Le);
  		 break;

  	// computes r
  	// sends r back to terminal
 	 case INS_GETR: // test
   		 if (!CheckCase(2))
   			ExitSW(ERR_CHECK_CASE);

 		 compute_r((BYTE*)ls.l1, (BYTE*)ls.l1);
 		 memcpy(apdu_data, (BYTE*)&r, CURVE_SIZE);

 		 ExitLa(Le);
 		 break;

 	// computes c (r is being computed within computing c)
 	// send back c, exponent of c, r, revocation attribute
 	 case INS_GETC: // test
   		 if (!CheckCase(2))
   			ExitSW(ERR_CHECK_CASE);

		 compute_c();
		 memcpy(apdu_data, (BYTE*)&c, CURVE_POINT_SIZE);

		 memcpy(apdu_data+CURVE_POINT_SIZE, (BYTE*)tmp.ecc_multiplier, CURVE_SIZE); // exponent of c
		 memcpy(apdu_data+CURVE_POINT_SIZE+CURVE_SIZE, (BYTE*)&r, CURVE_SIZE);
		 memcpy(apdu_data+CURVE_POINT_SIZE+2*CURVE_SIZE, (BYTE*)&attributes.attRev, CURVE_SIZE);

   		 ExitLa(Le);
   		 break;

   	// computes c
   	// creates random values rho_mR and rho_r
   	// computes t_revoke
   	// send back t_revoke and c
 	 case INS_GETTREVOKE: // test
   		 if (!CheckCase(2))
   			ExitSW(ERR_CHECK_CASE);

		 compute_c(); // computes c and stores it in c

		 getRandom_rho_mi((BYTE*)&rndNumbers.rhomR, 1); // computes rhomR
		 getRandom_rho_r();

		 comProofTRevoke();
		 memcpy(apdu_data, (BYTE*)&c, CURVE_POINT_SIZE);
		 memcpy(apdu_data+CURVE_POINT_SIZE, (BYTE*)&t_revoke, CURVE_POINT_SIZE); // copying to apdu data

		 memcpy(apdu_data+2*CURVE_POINT_SIZE, (BYTE*)&rndNumbers.rhomR.ecc_multiplier, CURVE_SIZE);
		 memcpy(apdu_data+2*CURVE_POINT_SIZE+CURVE_SIZE, (BYTE*)&rndNumbers.rhor.ecc_multiplier, CURVE_SIZE);

   		 ExitLa(Le);
   		 break;

   	// generates random rho_r and rho_mR
   	// computes t_revoke
   	// computes sr, smr
    // sends back to terminal sr, smr, rho_r, rho_mR, e, r
 	 case INS_GETSFORREV: // test
   		 if (!CheckCase(2))
   			ExitSW(ERR_CHECK_CASE);

   		 getRandom_rho_r();
   		 getRandom_rho_mi((BYTE*)&rndNumbers.rhomR, 1); // computes rhomR

   		 comProofTRevoke(); // test if they do not infulence each other
   		 memcpy(apdu_data+CURVE_POINT_SIZE, (BYTE*)&t_revoke, CURVE_POINT_SIZE); // copying to apdu data

 		 comProofSr(); // stored in nonce, store in apdu as first CURVE_SIZE
 		 memcpy(apdu_data, (BYTE*)&sr, CURVE_SIZE);

 		 comProofSmr(); // stored in nonce, store in apdu as second CURVE_SIZE
 		 memcpy(apdu_data+CURVE_SIZE, (BYTE*)&smr, CURVE_SIZE);

 		 memcpy(apdu_data+2*CURVE_SIZE, (BYTE*)&rndNumbers.rhor.ecc_multiplier, CURVE_SIZE);
 		 memcpy(apdu_data+3*CURVE_SIZE, (BYTE*)&rndNumbers.rhomR.ecc_multiplier, CURVE_SIZE);
 		 memcpy(apdu_data+4*CURVE_SIZE, (BYTE*)&e, CURVE_SIZE);
 		 memcpy(apdu_data+5*CURVE_SIZE, (BYTE*)&r, CURVE_SIZE);

   		 ExitLa(Le);
   		 break;

  	 default:
  		 ExitSW(ERR_BAD_INS);
  }
}


/*
 * Generate attributes to the buffer of attributes,
 * All attributes have size of CURVE_SIZE = 24B
 *
 * @param buffer to store generated attributes
 * @param number of issued attributes
 */
void generateAttributes(BYTE *buffer, BYTE number){

	BYTE numbertmp = 0;

	while(numbertmp < number){			//cycle while is faster than cycle for!

		__push(buffer);
		__code(PRIM, __PRIM_RANDOM_NUMBER);
		__code(PRIM, __PRIM_RANDOM_NUMBER);
		__code(PRIM, __PRIM_RANDOM_NUMBER);
		__code(STOREI, CURVE_SIZE);
		buffer = buffer + CURVE_SIZE;
		numbertmp++;
	}
}


/**
 * Generate a random number to the rndNumbers.v.ecc_multiplier (size = CURVE_SIZE = 24B),
 *
 */
void getRandom_v(void){

	// putting to the cycle for: for(i = 0; i<CURVE_SIZE/RANDOM_NUMBER_BLOCK; i++) __code(PRIM, 0xc4); // is slower
	__code(PRIM, 0xc4);											//push 8 random bytes  				(stack:   8  bytes)
	__code(PRIM, 0xc4);											//push 8 random bytes  				(stack:   16 bytes)
	__code(PRIM, 0xc4);											//push 8 random bytes  				(stack:   24 bytes)
	__code (STORE, rndNumbers.v.ecc_multiplier, CURVE_SIZE);	//pop CURVE_SIZE bytes into rndNumbers.v (stack:   0 bytes)

}


/**
 * Generate a random number to the rndNumbers.rhov.ecc_multiplier (size = CURVE_SIZE = 24B),
 *
 */
void getRandom_rho_v(void){

	// putting to the cycle for: for(i = 0; i<CURVE_SIZE/RANDOM_NUMBER_BLOCK; i++) __code(PRIM, 0xc4); // is slower
	__code(PRIM, 0xc4);                 						//push 8 random bytes  				(stack:   8  bytes)
	__code(PRIM, 0xc4);											//push 8 random bytes  				(stack:   16 bytes)
	__code(PRIM, 0xc4);											//push 8 random bytes  				(stack:   24 bytes)
	__code (STORE, rndNumbers.rhov.ecc_multiplier, CURVE_SIZE);	//pop CURVE_SIZE bytes into rndNumbers.rhov (stack:   0 bytes)

}

/**
 * Generate random numbers to the buffer of rndNumbers.romi,
 * All random numbers are in the form: 0x00||RANDOM_NUMBER||0x00||RANDOM_NUMBER ..., where |RANDOM_NUMBER|=CURVE_SIZE=24B
 * Particular form is necessary for ECC point operations
 *
 * @param buffer to store the generated random number
 * @param number of proved attributes
 */
void getRandom_rho_mi(BYTE *buffer, BYTE numProveAtt){

	BYTE numProveAtttmp = 0;
	buffer = buffer +1;

	while(numProveAtttmp < numProveAtt){			//cycle while is faster than cycle for! (more less 50 ms in case 5 issued attributes and 2 disclosed attributes)

		__push(buffer);
		__code(PRIM, __PRIM_RANDOM_NUMBER);
		__code(PRIM, __PRIM_RANDOM_NUMBER);
		__code(PRIM, __PRIM_RANDOM_NUMBER);
		__code(STOREI, CURVE_SIZE);
		buffer = buffer + (CURVE_SIZE + 1);
		numProveAtttmp++;
	}
}


/**
 * Compute proof t = suma_undisclosed_att_i(signature_i * romi)
 *
 * @param buffer_rndNumbers buffer of random numbers
 * @param buffer_signatures buffer of stored signatures
 */
void comSigmaXi(BYTE *buffer_rndNumbers, BYTE *buffer_signatures){

	BYTE tmp = 1;

	if(numProveAtt == 0x00) return;



	__push (ecDomainParams);
	__push (buffer_signatures);
	__push (buffer_rndNumbers);
	__push ((BYTE*)&t_verify);
	__code (PRIM, __PRIM_ECC_SCALAR_MULTIPLICATION);


	while(tmp < numProveAtt){			//cycle while is faster than cycle for!

		buffer_rndNumbers = buffer_rndNumbers + (CURVE_SIZE + 1);
		buffer_signatures = buffer_signatures + CURVE_POINT_SIZE;

		__push (ecDomainParams);
		__push (buffer_signatures);
		__push (buffer_rndNumbers);
		__push ((BYTE*)&tempPoint);
		__code (PRIM, __PRIM_ECC_SCALAR_MULTIPLICATION);

		__push (ecDomainParams);
		__push ((BYTE*)&t_verify);
		__push ((BYTE*)&tempPoint);
		__push ((BYTE*)&t_verify);
		__code (PRIM, __PRIM_ECC_ADDITION);

		tmp++;

	}
}


/**
 * Compute proof t: t = (suma_undisclosed_att_i(signature_i * rhomi) * r ) + rhov * pointG
 * Output is stored to the apdu_data
 *
 * @param numProveAtt number of proved attributes (undisclosed attributes)
 */
void comProofTVerify(BYTE numProveAtt ){

	comSigmaXi((BYTE*)&rndNumbers.rhomR, (BYTE*)&signatures.sigRev);

	//compute  t' = rhov * pointG
	__push (ecDomainParams);
	__push ((BYTE*)&pointG);
	__push ((BYTE*)&rndNumbers.rhov);
	__push (apdu_data);
	__code (PRIM, __PRIM_ECC_SCALAR_MULTIPLICATION);

	if(numProveAtt == 0x00) return;

	//compute  t = v * proof.t
	__push (ecDomainParams);
	__push ((BYTE*)&t_verify);
	__push ((BYTE*)&rndNumbers.v);
	__push ((BYTE*)&t_verify);
	__code (PRIM, __PRIM_ECC_SCALAR_MULTIPLICATION);

	//compute  t = t + t'
	__push (ecDomainParams);
	__push ((BYTE*)&t_verify);
	__push (apdu_data);
	__push (apdu_data);
	__code (PRIM, __PRIM_ECC_ADDITION);

}

/**
 * Compute proof sv = rhov + e*v mod q
 *
 */
void comProofSv(void){

	 __code(PUSHZ, CURVE_SIZE);                          			//push 24 bytes zeros   (stack:  24 bytes: 0:24)
	 __push(BLOCKCAST(CURVE_SIZE) (rndNumbers.rhov.ecc_multiplier));//push 24 bytes rhov    (stack:  48 bytes: rhov:48)
	 __push(BLOCKCAST(CURVE_SIZE) e);      		        			//push 24 bytes e    	(stack:  72 bytes: rhov:48, e:24)
	 __push(BLOCKCAST(CURVE_SIZE) (rndNumbers.v.ecc_multiplier));   //push 24 bytes v      	(stack:  96 bytes: rhov:48, e:24, v:24)
	 __code(PRIM, 0x10, CURVE_SIZE);                     			//multiply e*v    		(stack:  96 bytes: rhov:48, e*v:48)
	 __code(ADDN, 2*CURVE_SIZE);                         			//add              		(stack:  96 bytes: rhov+e*v:48, e*v:48)
	 __code(POPN, 2*CURVE_SIZE);                           			//pop 48 bytes          (stack:  48 bytes: rhov+e*v:48)
	 __code(STORE, z, 2*CURVE_SIZE);								//pop 24 bytes to z     (stack:   0 bytes)

	 ModularReduction(2*CURVE_SIZE, 2*CURVE_SIZE, z, modOrder);

	 memcpy(apdu_data+4*CURVE_POINT_SIZE+CURVE_SIZE, z+CURVE_SIZE, CURVE_SIZE);	// 	apdu_data: pi.t||sigmaRND||pi.e||sv (stack:   146 bytes)
}

/**
 * Compute proofs smi, for i = 1,2,3,...10, smi = romi - e* mi
 * Output is stored to the apdu_data
 *
 *@param buffer_attribute buffer of stored attributes
 *@param buffer_rndNumbers buffer of stored random numbers
 *@param buffer_apdu output apdu buffer, output proof are stored there
 */
void comProofSmi(BYTE *buffer_attribute, BYTE *buffer_rndNumbers, BYTE *buffer_apdu){

	BYTE tmp = 0;
	buffer_rndNumbers = buffer_rndNumbers +1;

	while(tmp < numProveAtt){			//cycle while is faster than cycle for!

			__push(BLOCKCAST(CURVE_SIZE) e);      						    //push 25 bytes e    	(stack:  25 bytes: e:25)
			__push(BLOCKCAST(CURVE_SIZE) buffer_attribute);     		    //push 25 bytes m1     	(stack:  50 bytes: e:25, m:25)
			__code(PRIM, 0x10, CURVE_SIZE);                     			//multiply e*m1    		(stack:  50 bytes: e*m1:50)
			__code(PUSHZ, CURVE_SIZE);                          			//push 25 bytes zeros   (stack:  75 bytes: e*m1:50, 0:25)
			__push(BLOCKCAST(CURVE_SIZE) buffer_rndNumbers);                //push 25 bytes rom1    (stack: 100 bytes: e*m1:50, rom1:50)
			__code(SUBN, 2*CURVE_SIZE);                         			//subtract              (stack: 100 bytes: e*m1-rhom1:50, rom1:50)
			__code(POPN, 2*CURVE_SIZE);                           			//pop 50 bytes          (stack:  50 bytes: e*m1-rhom1:50)
			__code(STORE, z, 2*CURVE_SIZE);									//pop 50 bytes to z     (stack:   0 bytes)


			ModularReduction(2*CURVE_SIZE, 2*CURVE_SIZE, z, modOrder);			// e*m1 - rhom1 mod q
			memcpy(buffer_apdu, z+CURVE_SIZE, CURVE_SIZE);

			__push(buffer_apdu);
			__push(BLOCKCAST(CURVE_SIZE) (BYTE*) (ecDomainParams+OFFSET_EC_DomainParams_N));   //push 25 bytes q	(stack:  25 bytes: q:25)
			__push(BLOCKCAST(CURVE_SIZE) buffer_apdu);     				    //push 25 bytes sm1 (stack:  25 bytes: q:25, sm1:25)
			__code(SUBN, CURVE_SIZE);                         				//subtract          (stack:  50 bytes: q-sm1:25, sm1:25)
			__code(POPN, CURVE_SIZE);										//pop 25 bytes      (stack:  25 bytes: q-sm1:25)
			__code(STOREI, CURVE_SIZE);

			buffer_attribute = buffer_attribute + CURVE_SIZE;
			buffer_rndNumbers = buffer_rndNumbers + (CURVE_SIZE + 1);
			buffer_apdu = buffer_apdu + CURVE_SIZE;
			tmp++;
	}
}

// REVOCATION PROTOCOL FUNCTIONS

void getRandom_rho_r(void){
	__code(PRIM, 0xc4);                 						//push 8 random bytes  				(stack:   8  bytes)
	__code(PRIM, 0xc4);											//push 8 random bytes  				(stack:   16 bytes)
	__code(PRIM, 0xc4);											//push 8 random bytes  				(stack:   24 bytes)
	__code (STORE, rndNumbers.rhor.ecc_multiplier, CURVE_SIZE);	//pop CURVE_SIZE bytes into rndNumbers.rhor (stack:   0 bytes)
}


// requires alphas and ls to be computed
// (numPrevVerifications % 10) gets second digit of number (0,1,2,3,..)
// (numPrevVerifications/10)   gets first  digit of num (0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,...)
void compute_r(BYTE *buffer_firstL, BYTE *buffer_secondL){

	 buffer_firstL = buffer_firstL + (numPrevVerifications % 10)*CURVE_SIZE;
	 buffer_secondL = buffer_secondL + (numPrevVerifications / 10)*CURVE_SIZE;

     __push(BLOCKCAST(CURVE_SIZE) (BYTE*)alphas.alpha1);    //push 24 bytes alpha1     	(stack:  24 bytes: alpha1:24)
	 __push(BLOCKCAST(CURVE_SIZE) buffer_firstL);           //push 24 bytes l(1-10)    	(stack:  48 bytes: alpha1:24, l_x:24)
	 __code(PRIM, 0x10, CURVE_SIZE);                        //multiply alpha1*l_x   	(stack:  48 bytes: alpha1*l_x:48)
	 __push(BLOCKCAST(CURVE_SIZE) (BYTE*)alphas.alpha2);    //push 24 bytes alpha2     	(stack:  72 bytes: alpha1*l_x:48, alpha2:24)
     __push(BLOCKCAST(CURVE_SIZE) buffer_secondL);          //push 24 bytes l(1-10)    	(stack:  96 bytes: alpha1*l_x:48, alpha2:24, l_y:24)
	 __code(PRIM, 0x10, CURVE_SIZE);                        //multiply alpha2*l_y    	(stack:  96 bytes: alpha1*l_x:48, alpha2*l_y:48)
	 __code(ADDN, 2*CURVE_SIZE);                            //add              		    (stack:  96 bytes: alpha1*l_x+alpha2*l_y:48, alpha2*l_y:48)
	 __code(POPN, 2*CURVE_SIZE);                           	//pop 48 bytes              (stack:  48 bytes: alpha1*l_x+alpha2*l_y:48)
	 __code(STORE, z, 2*CURVE_SIZE);					    //pop 48 bytes to z         (stack:   0 bytes)

	 ModularReduction(2*CURVE_SIZE, 2*CURVE_SIZE, z, modOrder); // stores only in the fourth part, as reduced size is CURVE_SIZE
	 //memcpy(apdu_data, z+CURVE_SIZE, CURVE_SIZE);
	 memcpy((BYTE*)&r, z+CURVE_SIZE, CURVE_SIZE);
}

// requires ls and alphas to ba computed
// requires epoch to be stored
// requires attRev to be computed
void compute_c(void){
	 // compute r (which is unique for this epoch) from numPrevVerifications: function sets pointers different from l1 according to numPrevVerifications
	 compute_r((BYTE*)ls.l1, (BYTE*)ls.l1);

	 __push(BLOCKCAST(CURVE_SIZE) r);     		                             //push 24 bytes r     	    (stack:  24 bytes: r:24)
	 __push(BLOCKCAST(CURVE_SIZE) (BYTE*)attributes.attRev);                 //push 24 bytes attRev     (stack:  48 bytes: r:24, attRev:24)
	 __code(SUBN, CURVE_SIZE);                         			             //subtract                 (stack:  48 bytes: r-attRev:24, attRev:24)
	 __code(POPN, CURVE_SIZE);                           			         //pop 24 bytes             (stack:  24 bytes: r-attRev:24)

	 __push(BLOCKCAST(CURVE_SIZE) (BYTE*)epochHash);     		             //push 24 bytes currentEpoch (stack:  48 bytes: r-attRev:24, epochHash:24)
	 __code(ADDN, CURVE_SIZE);                         			             //add                        (stack:  48 bytes: r-attRev+epochHash:24, epochHash:24)
	 __code(POPN, CURVE_SIZE);                           			         //pop 24 bytes               (stack:  24 bytes: r-attRev+epochHash:24)
	 __code(STORE, tmp.ecc_multiplier, CURVE_SIZE);					         //pop 48 bytes to z        (stack:   0 bytes)

	 // compute modular inverse of z stored in tmp
	 __push(CURVE_SIZE);                              //push modulus length CURVE_SIZE
	 __push(ecDomainParams+OFFSET_EC_DomainParams_N); //push 24 bytes q	(stack:  24 bytes: q:24)
	 __push(CURVE_SIZE);                              //input length
	 __push((BYTE*)&tmp.ecc_multiplier);              //input
	 __push((BYTE*)&tmp.ecc_multiplier);              //store result in tmp
	 __code(PRIM, 0xD0, 1);                           //set to 1 as modulus is prime

	 //compute (c = pointG * exp_c) and store in c, c = pointG * exp_c
	 __push (ecDomainParams);
	 __push ((BYTE*)&pointG);
	 __push ((BYTE*)&tmp);
	 __push ((BYTE*)&c);
	 __code (PRIM, __PRIM_ECC_SCALAR_MULTIPLICATION);
}

    // t_revoke = c^(rho_mR) c^(rho_r)
	// requires c to be computed
	// requires rhor to be computed
	// requires rho_mR to be computed
    void comProofTRevoke(void){

	//compute  t' = rhor * c
	__push (ecDomainParams); // domain parameters, stay always the same
	__push ((BYTE*)&c); // must be an ECPoint
	__push ((BYTE*)&rndNumbers.rhor);
	__push ((BYTE*)&tempPoint); // address where to send, curve point already stored c
	__code (PRIM, __PRIM_ECC_SCALAR_MULTIPLICATION);

	//compute  t = rho_mR * c
	// TODO: at this point, rhomR has to be computed already!
	__push (ecDomainParams);
	__push ((BYTE*)&c);
	__push ((BYTE*)&rndNumbers.rhomR);
	__push ((BYTE*)&t_revoke);
	__code (PRIM, __PRIM_ECC_SCALAR_MULTIPLICATION);

	//compute  t = t + t'
	__push (ecDomainParams);
	__push ((BYTE*)&t_revoke);
	__push ((BYTE*)&tempPoint); // t_verify = c^rhor + c
	__push ((BYTE*)&t_revoke); // storing computed t_verify in t_verify
	__code (PRIM, __PRIM_ECC_ADDITION);
}

// s_mR = rho_r + e*r
// requires mR to be computed
// requires rhomR to be computed
// requires e to be computed
// stores in smr in EEPROM
void comProofSmr(void){
	 __push(BLOCKCAST(CURVE_SIZE) e);      		        			    //push 24 bytes e    	   (stack:  24 bytes: e:24)
	 __push(BLOCKCAST(CURVE_SIZE) (BYTE*)&attributes.attRev);           //push 24 bytes attrRev    (stack:  48 bytes: e:24, attRev:24)
	 __code(PRIM, 0x10, CURVE_SIZE);                     			    //multiply e*attrRev       (stack:  48 bytes: e*attRev:48)
	 __code(STORE, z, 2*CURVE_SIZE);								    //pop 48 bytes to z        (stack:   0 bytes)

	 ModularReduction(2*CURVE_SIZE, 2*CURVE_SIZE, z, modOrder);
	 memcpy((BYTE*)&tmp.ecc_multiplier, z+CURVE_SIZE, CURVE_SIZE); // TODO: rename the tmp to something more suitable, or store somewhere more suitable

	 __push(BLOCKCAST(CURVE_SIZE) (rndNumbers.rhomR.ecc_multiplier)); //push 24 bytes rhomR       (stack:  24 bytes: rhomR:24)
	 __push(BLOCKCAST(CURVE_SIZE) tmp.ecc_multiplier);        //push 24 bytes e*attRev    (stack:  48 bytes: rhomR:24, e*attRev:24)
	 __code(SUBN, CURVE_SIZE);                         			      //subtract           	      (stack:  48 bytes: rhomR-e*attRev:24, e*attRev:24)
	 __code(POPN, CURVE_SIZE);                           			  //pop 48 bytes              (stack:  24 bytes: rhomR-e*attRev:24)
	 __code(STORE, smr, CURVE_SIZE);		          //pop 24 bytes to apdu_data (stack:   0 bytes)

	 //memcpy(apdu_data+CURVE_SIZE, z+CURVE_SIZE, CURVE_SIZE);	// 	apdu_data: s_r || s_mR
}

// s_r = rho_r + e*r
// requires r to be computed
// requires rhor to be computed
// requires e to be computed
// stores in sr in EEPROM
void comProofSr(void){
	 __code(PUSHZ, CURVE_SIZE);                          			//push 24 bytes zeros   (stack:  24 bytes: 0:24)
	 __push(BLOCKCAST(CURVE_SIZE) (rndNumbers.rhor.ecc_multiplier));//push 24 bytes rhor    (stack:  48 bytes: rhor:48)
	 __push(BLOCKCAST(CURVE_SIZE) e);      		        			//push 24 bytes e    	(stack:  72 bytes: rhor:48, e:24)
	 __push(BLOCKCAST(CURVE_SIZE) r);                         //push 24 bytes r      	(stack:  96 bytes: rhor:48, e:24, r:24)
	 __code(PRIM, 0x10, CURVE_SIZE);                     			//multiply e*r    		(stack:  96 bytes: rhor:48, e*r:48)
	 __code(ADDN, 2*CURVE_SIZE);                         			//add              		(stack:  96 bytes: rhor+e*r:48, e*r:48)
	 __code(POPN, 2*CURVE_SIZE);                           			//pop 48 bytes          (stack:  48 bytes: rhor+e*r:48)
	 __code(STORE, z, 2*CURVE_SIZE);								//pop 24 bytes to z     (stack:   0 bytes)

	 ModularReduction(2*CURVE_SIZE, 2*CURVE_SIZE, z, modOrder);

	 memcpy((BYTE*)&sr, z+CURVE_SIZE, CURVE_SIZE);	// 	apdu_data: s_r
}

