/* 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.
 *
 */

/* Implements ECC over Z/pZ for curve y^2 = x^3 + a*x + b
 *
 */

#include "tomcrypt.h"

#ifdef LTC_MECC

/** Import raw public or private key (public keys = ANSI X9.63 compressed or uncompressed; private keys = raw bytes)
  @param in     The input data to read
  @param inlen  The length of the input data
  @param key    [out] destination to store imported key
  @param dp     Curve parameters
  Return        CRYPT_OK on success
*/

int ecc_import_raw(const unsigned char *in, unsigned long inlen, ecc_key *key, ltc_ecc_set_type *dp)
{
   int err, type = -1;
   unsigned long size = 0;
   void *prime, *a, *b;
   ecc_point *base;

   LTC_ARGCHK(in  != NULL);
   LTC_ARGCHK(key != NULL);
   LTC_ARGCHK(dp  != NULL);

   /* init key + temporary numbers */
   if (mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k, &prime, &a, &b, NULL) != CRYPT_OK) {
      return CRYPT_MEM;
   }

   if (inlen <= (unsigned long)dp->size) {
      /* read PRIVATE key */
      type = PK_PRIVATE;
      size = inlen;
      /* load private k */
      if ((err = mp_read_unsigned_bin(key->k, (unsigned char *)in, size)) != CRYPT_OK) {
         goto cleanup;
      }
      if (mp_iszero(key->k)) {
         err = CRYPT_INVALID_PACKET;
         goto cleanup;
      }
      /* init base point */
      if ((base = ltc_ecc_new_point()) == NULL) {
         err = CRYPT_MEM;
         goto cleanup;
      }
      /* load prime + base point */
      if ((err = mp_read_radix(prime, dp->prime, 16)) != CRYPT_OK)                       { goto cleanup; }
      if ((err = mp_read_radix(base->x, dp->Gx, 16)) != CRYPT_OK)                        { goto cleanup; }
      if ((err = mp_read_radix(base->y, dp->Gy, 16)) != CRYPT_OK)                        { goto cleanup; }
      if ((err = mp_set(base->z, 1)) != CRYPT_OK)                                        { goto cleanup; }
      /* make the public key */
      if ((err = mp_read_radix(a, dp->A, 16)) != CRYPT_OK)                               { goto cleanup; }
      if ((err = ltc_mp.ecc_ptmul(key->k, base, &key->pubkey, a, prime, 1)) != CRYPT_OK) { goto cleanup; }
      /* cleanup */
      ltc_ecc_del_point(base);
   }
   else {
      /* read PUBLIC key */
      type = PK_PUBLIC;
      /* load prime + A + B */
      if ((err = mp_read_radix(prime, dp->prime, 16)) != CRYPT_OK)                       { goto cleanup; }
      if ((err = mp_read_radix(b, dp->B, 16)) != CRYPT_OK)                               { goto cleanup; }
      if ((err = mp_read_radix(a, dp->A, 16)) != CRYPT_OK)                               { goto cleanup; }
      err = ltc_ecc_import_point(in, inlen, prime, a, b, key->pubkey.x, key->pubkey.y);
      if (err != CRYPT_OK)                                                               { goto cleanup; }
      if ((err = mp_set(key->pubkey.z, 1)) != CRYPT_OK)                                  { goto cleanup; }
   }

   if ((err = ltc_ecc_is_point(dp, key->pubkey.x, key->pubkey.y)) != CRYPT_OK) {
      err = CRYPT_INVALID_PACKET;
      goto cleanup;
   }

   key->type = type;
   key->idx  = -1;
   key->dp   = dp;

   /* we're done */
   mp_clear_multi(prime, a, b, NULL);
   return CRYPT_OK;
cleanup:
   mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, prime, a, b, NULL);
   return err;
}

#endif
