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

/** Returns whether [x,y] is a point on curve defined by dp
  @param dp     curve parameters
  @param x      x point coordinate
  @param y      y point coordinate
  @return CRYPT_OK if valid
*/

int ltc_ecc_is_point(const ltc_ecc_set_type *dp, void *x, void *y)
{
  void *prime, *a, *b, *t1, *t2;
  int err;

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

  /* load prime, a and 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;

  /* compute y^2 */
  if ((err = mp_sqr(y, t1)) != CRYPT_OK)                               goto cleanup;

  /* compute x^3 */
  if ((err = mp_sqr(x, t2)) != CRYPT_OK)                               goto cleanup;
  if ((err = mp_mod(t2, prime, t2)) != CRYPT_OK)                       goto cleanup;
  if ((err = mp_mul(x, t2, t2)) != CRYPT_OK)                           goto cleanup;

  /* compute y^2 - x^3 */
  if ((err = mp_sub(t1, t2, t1)) != CRYPT_OK)                          goto cleanup;

  /* compute y^2 - x^3 - a*x */
  if ((err = mp_submod(prime, a, prime, t2)) != CRYPT_OK)              goto cleanup;
  if ((err = mp_mulmod(t2, x, prime, t2)) != CRYPT_OK)                 goto cleanup;
  if ((err = mp_addmod(t1, t2, prime, t1)) != CRYPT_OK)                goto cleanup;

  /* adjust range (0, prime) */
  while (mp_cmp_d(t1, 0) == LTC_MP_LT) {
     if ((err = mp_add(t1, prime, t1)) != CRYPT_OK)                    goto cleanup;
  }
  while (mp_cmp(t1, prime) != LTC_MP_LT) {
     if ((err = mp_sub(t1, prime, t1)) != CRYPT_OK)                    goto cleanup;
  }

  /* compare to b */
  if (mp_cmp(t1, b) != LTC_MP_EQ) {
     err = CRYPT_INVALID_PACKET;
  } else {
     err = CRYPT_OK;
  }

cleanup:
  mp_clear_multi(prime, a, b, t1, t2, NULL);
  return err;
}

#endif
