/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */

#include "tomcrypt_private.h"

/* origin of this code - OLPC */

#ifdef LTC_MECC

/**
  Verify a key according to ANSI spec
  @param key     The key to validate
  @return CRYPT_OK if successful
*/

int ltc_ecc_verify_key(const ecc_key *key)
{
   int err, inf;
   ecc_point *point;
   void *prime = key->dp.prime;
   void *order = key->dp.order;
   void *a     = key->dp.A;

   /* Test 1: Are the x and y points of the public key in the field? */
   if (ltc_mp.compare_d(key->pubkey.z, 1) == LTC_MP_EQ) {
      if ((ltc_mp.compare(key->pubkey.x, prime) != LTC_MP_LT) ||
          (ltc_mp.compare(key->pubkey.y, prime) != LTC_MP_LT) ||
          (ltc_mp.compare_d(key->pubkey.x, 0) == LTC_MP_LT) ||
          (ltc_mp.compare_d(key->pubkey.y, 0) == LTC_MP_LT) ||
          (mp_iszero(key->pubkey.x) && mp_iszero(key->pubkey.y))
         )
      {
         err = CRYPT_INVALID_PACKET;
         goto done2;
      }
   }

   /* Test 2: is the public key on the curve? */
   if ((err = ltc_ecc_is_point(&key->dp, key->pubkey.x, key->pubkey.y)) != CRYPT_OK)      { goto done2; }

   /* Test 3: does nG = O? (n = order, O = point at infinity, G = public key) */
   point = ltc_ecc_new_point();
   if ((err = ltc_ecc_mulmod(order, &(key->pubkey), point, a, prime, 1)) != CRYPT_OK)     { goto done1; }

   err = ltc_ecc_is_point_at_infinity(point, prime, &inf);
   if (err != CRYPT_OK || inf) {
      err = CRYPT_ERROR;
   }
   else {
      err = CRYPT_OK;
   }

done1:
   ltc_ecc_del_point(point);
done2:
   return err;
}

#endif
