/* LibTomCrypt, modular cryptographic library -- Tom St Denis
 *
 * LibTomCrypt is a library that provides various cryptographic
 * algorithms in a highly modular and flexible manner.
 *
 * The library is free for all purposes without any express
 * guarantee it works.
 *
 * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
 */

/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
 *
 * All curves taken from NIST recommendation paper of July 1999
 * Available at http://csrc.nist.gov/cryptval/dss.htm
 */
#include "tomcrypt.h"

/**
  @file ltc_ecc_projective_dbl_point.c
  ECC Crypto, Tom St Denis
*/  

#if defined(LTC_MECC) && (!defined(LTC_MECC_ACCEL) || defined(LTM_LTC_DESC))
int ltc_ecc_projective_dbl_kpoint(ecc_point *P, ecc_point *R, void *modulus, void *mp, void * a)
{
   void *t1, *t2 , * temp, *t4, *t5, * modmin3 , * number, * mu ,* orgZ;
   int err;
   unsigned char str[600];

   LTC_ARGCHK(P       != NULL);
   LTC_ARGCHK(R       != NULL);
   LTC_ARGCHK(modulus != NULL);
   LTC_ARGCHK(mp      != NULL);
   LTC_ARGCHK(a      != NULL);

   if ((err = mp_init_multi(&t1, &t2, &temp, &t4,&t5, &modmin3,&number, &orgZ,  NULL)) != CRYPT_OK) {
      return err;
   }


    if ((err = mp_init(&mu)) != CRYPT_OK) {
      return err;
   }
   if ((err = mp_montgomery_normalization(mu, modulus)) != CRYPT_OK) {
      mp_montgomery_free(mp);
      mp_clear(mu);
      return err;
   }
   
   if ((err = mp_copy(P->z, orgZ)) != CRYPT_OK)                                   { goto done; }
   if (P != R) {
      if ((err = mp_copy(P->x, R->x)) != CRYPT_OK)                                   { goto done; }
      if ((err = mp_copy(P->y, R->y)) != CRYPT_OK)                                   { goto done; }
      if ((err = mp_copy(P->z, R->z)) != CRYPT_OK)                                   { goto done; }
     
   }
   
   
  
  /* t1 = Z * Z */
   if ((err = mp_sqr(R->z, t1)) != CRYPT_OK)                                      { goto done; }
  
   if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK)                 { goto done; }
   
   /* Z = Y * Z */
   if ((err = mp_mul(R->z, R->y, R->z)) != CRYPT_OK)                              { goto done; }
   if ((err = mp_montgomery_reduce(R->z, modulus, mp)) != CRYPT_OK)               { goto done; }
  
   /* Z = 2Z */
   if ((err = mp_add(R->z, R->z, R->z)) != CRYPT_OK)                              { goto done; }
   if (mp_cmp(R->z, modulus) != LTC_MP_LT) {
      if ((err = mp_sub(R->z, modulus, R->z)) != CRYPT_OK)                        { goto done; }
   }
   
	#if 1

  if(( err =mp_set(number,3)) != CRYPT_OK)                                     { goto done; }

   if(( err = mp_sub(modulus,number,modmin3)) != CRYPT_OK)                        { goto done; }
 if(mp_cmp(a,modmin3) == LTC_MP_EQ)
   {

 		 /* T2 = X - T1 -> x - z^2 -> 5.4*/
		 if ((err = mp_sub(R->x, t1, t2)) != CRYPT_OK)                                  { goto done; }
		 if (mp_cmp_d(t2, 0) == LTC_MP_LT) {
				if ((err = mp_add(t2, modulus, t2)) != CRYPT_OK)                            { goto done; }
		 }
     
   
		 /* T1 = X + T1 -> x + z^2 -> 5.5 */
		 if ((err = mp_add(t1, R->x, t1)) != CRYPT_OK)                                  { goto done; }
		 if (mp_cmp(t1, modulus) != LTC_MP_LT) {
				if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK)                            { goto done; }
		 }
     
		 /* T2 = T1 * T2  -> (x - z^2) * (x + z^2) = x^2 - z^4  -> 5.6*/
		 if ((err = mp_mul(t1, t2, t2)) != CRYPT_OK)                                    { goto done; }
		 if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK)                 { goto done; }
		 
     /* T1 = 2T2 -> 2(x^2 - z^4) */
		 if ((err = mp_add(t2, t2, t1)) != CRYPT_OK)                                    { goto done; }
		 if (mp_cmp(t1, modulus) != LTC_MP_LT) {
				if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK)                            { goto done; }
		 }
		 
     /* T1 = T1 + T2 -> (x^2 - z^4) + 2(x^2 - z^4) = 3(x^2 - z^4) ->5.7 */
		 if ((err = mp_add(t1, t2, t1)) != CRYPT_OK)                                    { goto done; }
		 if (mp_cmp(t1, modulus) != LTC_MP_LT) {
				if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK)                            { goto done; }
		 }
      
	}
   #endif
	else /* for y^2 = x^3 + ax + b */
	{
	#if 1	
      /* T4 = a */
     if ((err = mp_copy(a, t4)) != CRYPT_OK)                                   { goto done; }
    // if ((err = mp_montgomery_reduce(t4, modulus, mp)) != CRYPT_OK)               { goto done; }
     if ((err = mp_mulmod(t4, mu, modulus, t4)) != CRYPT_OK)                   { goto done; }
     
    //debug
    err = mp_toradix(t4,str,16);
    //end debug
    /* T5 = T3 ^ 2 = */
     if ((err = mp_sqr(orgZ, t5)) != CRYPT_OK)                                      { goto done; }
		 if ((err = mp_montgomery_reduce(t5, modulus, mp)) != CRYPT_OK)               { goto done; }
     
       //debug
    err = mp_toradix(t5,str,16);
    //end debug
    	/* T5 = T5 ^ 2 -> z^4*/
		 if ((err = mp_sqr(t5, t5)) != CRYPT_OK)                                      { goto done; }
		 if ((err = mp_montgomery_reduce(t5, modulus, mp)) != CRYPT_OK)               { goto done; }
      //debug
    err = mp_toradix(t5,str,16);
    //end debug
		
     /*  (T5 = T4 * T5) -> a*z^4 */
		 if ((err = mp_mul(t4, t5, t5)) != CRYPT_OK)                                  { goto done; }
		 if ((err = mp_montgomery_reduce(t5, modulus, mp)) != CRYPT_OK)               { goto done; }
      //debug
    err = mp_toradix(t5,str,16);
    //end debug
		 
     /* T4 = T1 * T1 -> x^2  ( t1 = r->x)*/
		 if ((err = mp_sqr(P->x, t4)) != CRYPT_OK)                                      { goto done; }
		 if ((err = mp_montgomery_reduce(t4, modulus, mp)) != CRYPT_OK)               { goto done; }
   
      //debug
    err = mp_toradix(t4,str,16);
    //end debug
		 /*  (T4 = 3 * T4) -> 3*x^2 (2 steps) step 1 -> 2*x^2* -> temp = T4 + T4 */
		 if ((err = mp_add(t4, t4, temp)) != CRYPT_OK)                                   { goto done; }
		 if (mp_cmp(t4, modulus) != LTC_MP_LT) {
				if ((err = mp_sub(t4, modulus, temp)) != CRYPT_OK)                           { goto done; }
		 }
      //debug
    err = mp_toradix(temp,str,16);
    //end debug
     
			/* T4 = T4 + temp  step 2 -> 2x^2 + x^2 = 3*x^2 */
		 if ((err = mp_add(t4, temp, t4)) != CRYPT_OK)                                   { goto done; }
		 if (mp_cmp(t4, modulus) != LTC_MP_LT) {
				if ((err = mp_sub(t4, modulus, t4)) != CRYPT_OK)                           { goto done; }
		 }
		 
       //debug
    err = mp_toradix(t4,str,16);
    //end debug
    	/* (T4 = T4 + T5) -> 3x^2 + az^4 = M */
		 if ((err = mp_add(t4, t5, t4)) != CRYPT_OK)                                   { goto done; }
		 if (mp_cmp(t4, modulus) != LTC_MP_LT) {
				if ((err = mp_sub(t4, modulus, t4)) != CRYPT_OK)                           { goto done; }
		 }
		 //debug
    err = mp_toradix(t4,str,16);
    //end debug
      /* T1 = T3  -> to match Toms cod T1 = M   */
			if ((err = mp_copy(t4, t1)) != CRYPT_OK)                                   { goto done; }
      //debug
    err = mp_toradix(t1,str,16);
    //end debug
   #endif
	}
  
  

   /* Y = 2Y */
   if ((err = mp_add(R->y, R->y, R->y)) != CRYPT_OK)                              { goto done; }
   if (mp_cmp(R->y, modulus) != LTC_MP_LT) {
      if ((err = mp_sub(R->y, modulus, R->y)) != CRYPT_OK)                        { goto done; }
   }
   /* Y = Y * Y */
   if ((err = mp_sqr(R->y, R->y)) != CRYPT_OK)                                    { goto done; }
   if ((err = mp_montgomery_reduce(R->y, modulus, mp)) != CRYPT_OK)               { goto done; }
   /* T2 = Y * Y */
   if ((err = mp_sqr(R->y, t2)) != CRYPT_OK)                                      { goto done; }
   if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK)                 { goto done; }
   /* T2 = T2/2 */
   if (mp_isodd(t2)) {
      if ((err = mp_add(t2, modulus, t2)) != CRYPT_OK)                            { goto done; }
   }
   if ((err = mp_div_2(t2, t2)) != CRYPT_OK)                                      { goto done; }
   /* Y = Y * X */
   if ((err = mp_mul(R->y, R->x, R->y)) != CRYPT_OK)                              { goto done; }
   if ((err = mp_montgomery_reduce(R->y, modulus, mp)) != CRYPT_OK)               { goto done; }

   /* X  = T1 * T1 */
   if ((err = mp_sqr(t1, R->x)) != CRYPT_OK)                                      { goto done; }
   if ((err = mp_montgomery_reduce(R->x, modulus, mp)) != CRYPT_OK)               { goto done; }
   /* X = X - Y */
   if ((err = mp_sub(R->x, R->y, R->x)) != CRYPT_OK)                              { goto done; }
   if (mp_cmp_d(R->x, 0) == LTC_MP_LT) {
      if ((err = mp_add(R->x, modulus, R->x)) != CRYPT_OK)                        { goto done; }
   }
   /* X = X - Y */
   if ((err = mp_sub(R->x, R->y, R->x)) != CRYPT_OK)                              { goto done; }
   if (mp_cmp_d(R->x, 0) == LTC_MP_LT) {
      if ((err = mp_add(R->x, modulus, R->x)) != CRYPT_OK)                        { goto done; }
   }

   
   /* Y = Y - X */     
   if ((err = mp_sub(R->y, R->x, R->y)) != CRYPT_OK)                              { goto done; }
   if (mp_cmp_d(R->y, 0) == LTC_MP_LT) {
      if ((err = mp_add(R->y, modulus, R->y)) != CRYPT_OK)                        { goto done; }
   }
   /* Y = Y * T1 */
   if ((err = mp_mul(R->y, t1, R->y)) != CRYPT_OK)                                { goto done; }
   if ((err = mp_montgomery_reduce(R->y, modulus, mp)) != CRYPT_OK)               { goto done; }
   /* Y = Y - T2 */
   if ((err = mp_sub(R->y, t2, R->y)) != CRYPT_OK)                                { goto done; }
   if (mp_cmp_d(R->y, 0) == LTC_MP_LT) {
      if ((err = mp_add(R->y, modulus, R->y)) != CRYPT_OK)                        { goto done; }
   }
 
   err = CRYPT_OK;
   goto done;
done:
   mp_clear_multi(t1, t2, temp, t4, t5, modmin3, number, orgZ, NULL);
  
   mp_clear(mu);
   
   return err;
}

/**
   Double an ECC point
   @param P   The point to double
   @param R   [out] The destination of the double
   @param modulus  The modulus of the field the ECC curve is in
   @param mp       The "b" value from montgomery_setup()
   @return CRYPT_OK on success
*/
int ltc_ecc_projective_dbl_point(ecc_point *P, ecc_point *R, void *modulus, void *mp)
{
   void *t1, *t2;
   int   err;

   LTC_ARGCHK(P       != NULL);
   LTC_ARGCHK(R       != NULL);
   LTC_ARGCHK(modulus != NULL);
   LTC_ARGCHK(mp      != NULL);

   if ((err = mp_init_multi(&t1, &t2, NULL)) != CRYPT_OK) {
      return err;
   }

   if (P != R) {
      if ((err = mp_copy(P->x, R->x)) != CRYPT_OK)                                { goto done; }
      if ((err = mp_copy(P->y, R->y)) != CRYPT_OK)                                { goto done; }
      if ((err = mp_copy(P->z, R->z)) != CRYPT_OK)                                { goto done; }
   }

   /* t1 = Z * Z */
   if ((err = mp_sqr(R->z, t1)) != CRYPT_OK)                                      { goto done; }
   if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK)                 { goto done; }
   /* Z = Y * Z */
   if ((err = mp_mul(R->z, R->y, R->z)) != CRYPT_OK)                              { goto done; }
   if ((err = mp_montgomery_reduce(R->z, modulus, mp)) != CRYPT_OK)               { goto done; }
   /* Z = 2Z */
   if ((err = mp_add(R->z, R->z, R->z)) != CRYPT_OK)                              { goto done; }
   if (mp_cmp(R->z, modulus) != LTC_MP_LT) {
      if ((err = mp_sub(R->z, modulus, R->z)) != CRYPT_OK)                        { goto done; }
   }
   
   /* T2 = X - T1 */
   if ((err = mp_sub(R->x, t1, t2)) != CRYPT_OK)                                  { goto done; }
   if (mp_cmp_d(t2, 0) == LTC_MP_LT) {
      if ((err = mp_add(t2, modulus, t2)) != CRYPT_OK)                            { goto done; }
   }
   /* T1 = X + T1 */
   if ((err = mp_add(t1, R->x, t1)) != CRYPT_OK)                                  { goto done; }
   if (mp_cmp(t1, modulus) != LTC_MP_LT) {
      if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK)                            { goto done; }
   }
   /* T2 = T1 * T2 */
   if ((err = mp_mul(t1, t2, t2)) != CRYPT_OK)                                    { goto done; }
   if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK)                 { goto done; }
   /* T1 = 2T2 */
   if ((err = mp_add(t2, t2, t1)) != CRYPT_OK)                                    { goto done; }
   if (mp_cmp(t1, modulus) != LTC_MP_LT) {
      if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK)                            { goto done; }
   }
   /* T1 = T1 + T2 */
   if ((err = mp_add(t1, t2, t1)) != CRYPT_OK)                                    { goto done; }
   if (mp_cmp(t1, modulus) != LTC_MP_LT) {
      if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK)                            { goto done; }
   }

   /* Y = 2Y */
   if ((err = mp_add(R->y, R->y, R->y)) != CRYPT_OK)                              { goto done; }
   if (mp_cmp(R->y, modulus) != LTC_MP_LT) {
      if ((err = mp_sub(R->y, modulus, R->y)) != CRYPT_OK)                        { goto done; }
   }
   /* Y = Y * Y */
   if ((err = mp_sqr(R->y, R->y)) != CRYPT_OK)                                    { goto done; }
   if ((err = mp_montgomery_reduce(R->y, modulus, mp)) != CRYPT_OK)               { goto done; }
   /* T2 = Y * Y */
   if ((err = mp_sqr(R->y, t2)) != CRYPT_OK)                                      { goto done; }
   if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK)                 { goto done; }
   /* T2 = T2/2 */
   if (mp_isodd(t2)) {
      if ((err = mp_add(t2, modulus, t2)) != CRYPT_OK)                            { goto done; }
   }
   if ((err = mp_div_2(t2, t2)) != CRYPT_OK)                                      { goto done; }
   /* Y = Y * X */
   if ((err = mp_mul(R->y, R->x, R->y)) != CRYPT_OK)                              { goto done; }
   if ((err = mp_montgomery_reduce(R->y, modulus, mp)) != CRYPT_OK)               { goto done; }

   /* X  = T1 * T1 */
   if ((err = mp_sqr(t1, R->x)) != CRYPT_OK)                                      { goto done; }
   if ((err = mp_montgomery_reduce(R->x, modulus, mp)) != CRYPT_OK)               { goto done; }
   /* X = X - Y */
   if ((err = mp_sub(R->x, R->y, R->x)) != CRYPT_OK)                              { goto done; }
   if (mp_cmp_d(R->x, 0) == LTC_MP_LT) {
      if ((err = mp_add(R->x, modulus, R->x)) != CRYPT_OK)                        { goto done; }
   }
   /* X = X - Y */
   if ((err = mp_sub(R->x, R->y, R->x)) != CRYPT_OK)                              { goto done; }
   if (mp_cmp_d(R->x, 0) == LTC_MP_LT) {
      if ((err = mp_add(R->x, modulus, R->x)) != CRYPT_OK)                        { goto done; }
   }

   /* Y = Y - X */     
   if ((err = mp_sub(R->y, R->x, R->y)) != CRYPT_OK)                              { goto done; }
   if (mp_cmp_d(R->y, 0) == LTC_MP_LT) {
      if ((err = mp_add(R->y, modulus, R->y)) != CRYPT_OK)                        { goto done; }
   }
   /* Y = Y * T1 */
   if ((err = mp_mul(R->y, t1, R->y)) != CRYPT_OK)                                { goto done; }
   if ((err = mp_montgomery_reduce(R->y, modulus, mp)) != CRYPT_OK)               { goto done; }
   /* Y = Y - T2 */
   if ((err = mp_sub(R->y, t2, R->y)) != CRYPT_OK)                                { goto done; }
   if (mp_cmp_d(R->y, 0) == LTC_MP_LT) {
      if ((err = mp_add(R->y, modulus, R->y)) != CRYPT_OK)                        { goto done; }
   }
 
   err = CRYPT_OK;
done:
   mp_clear_multi(t1, t2, NULL);
   return err;
}
#endif
/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ltc_ecc_projective_dbl_point.c,v $ */
/* $Revision: 1.11 $ */
/* $Date: 2007/05/12 14:32:35 $ */

