Example #1
0
/* initialize single cache entry
 * for a curve with the given id */
static int
_ecc_wmnaf_cache_entry_init (gnutls_ecc_curve_cache_entry_t * p,
                             gnutls_ecc_curve_t id)
{
  int i, j, err;
  ecc_point *G;
  mpz_t a, modulus;

  const gnutls_ecc_curve_entry_st *st = NULL;

  if (p == NULL || id == 0)
    return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;

  G = ecc_new_point ();
  if (G == NULL)
    {
      return GNUTLS_E_MEMORY_ERROR;
    }

  st = _gnutls_ecc_curve_get_params (id);
  if (st == NULL)
    {
      err = GNUTLS_E_INTERNAL_ERROR;
      goto done;
    }

  if ((err = mp_init_multi (&a, &modulus, NULL) != 0))
    return err;

  /* set id */
  p->id = id;

  /* set modulus */
  mpz_set_str (modulus, st->prime, 16);

  /* get generator point */
  mpz_set_str (G->x, st->Gx, 16);
  mpz_set_str (G->y, st->Gy, 16);
  mpz_set_ui (G->z, 1);

  /* set A */
  mpz_set_str (a, st->A, 16);

  /* alloc ram for precomputed values */
  for (i = 0; i < WMNAF_PRECOMPUTED_LENGTH; ++i)
    {
      p->pos[i] = ecc_new_point ();
      p->neg[i] = ecc_new_point ();
      if (p->pos[i] == NULL || p->neg[i] == NULL)
        {
          for (j = 0; j < i; ++j)
            {
              ecc_del_point (p->pos[j]);
              ecc_del_point (p->neg[j]);
            }

          err = GNUTLS_E_MEMORY_ERROR;
          goto done;
        }
    }

  /* fill in pos and neg arrays with precomputed values
   * pos holds kG for k ==  1, 3, 5, ..., (2^w - 1)
   * neg holds kG for k == -1,-3,-5, ...,-(2^w - 1)
   */

  /* pos[0] == 2G for a while, later it will be set to the expected 1G */
  if ((err = ecc_projective_dbl_point (G, p->pos[0], a, modulus)) != 0)
    goto done;

  /* pos[1] == 3G */
  if ((err =
       ecc_projective_add_point (p->pos[0], G, p->pos[1], a,
                                    modulus)) != 0)
    goto done;

  /* fill in kG for k = 5, 7, ..., (2^w - 1) */
  for (j = 2; j < WMNAF_PRECOMPUTED_LENGTH; ++j)
    {
      if ((err =
           ecc_projective_add_point (p->pos[j - 1], p->pos[0], p->pos[j],
                                        a, modulus)) != 0)
        goto done;
    }

  /* set pos[0] == 1G as expected
   * after this step we don't need G at all */
  mpz_set (p->pos[0]->x, G->x);
  mpz_set (p->pos[0]->y, G->y);
  mpz_set (p->pos[0]->z, G->z);

  /* map to affine all elements in pos
   * this will allow to use ecc_projective_madd later
   * set neg[i] == -pos[i] */
  for (j = 0; j < WMNAF_PRECOMPUTED_LENGTH; ++j)
    {
      if ((err = ecc_map (p->pos[j], modulus)) != 0)
        goto done;

      if ((err =
           ecc_projective_negate_point (p->pos[j], p->neg[j], modulus)) != 0)
        goto done;
    }

  err = 0;
done:
  ecc_del_point (G);
  mp_clear_multi (&a, &modulus, NULL);

  return err;
}
Example #2
0
/*
   Perform a point wMNAF-multiplication utilizing cache
   This version tries to be timing resistant
   @param k    The scalar to multiply by
   @param id   The curve's id
   @param R    [out] Destination for kG
   @param a        The curve's A value
   @param modulus  The modulus of the field the ECC curve is in
   @param map      Boolean whether to map back to affine or not (1 == map, 0 == leave in projective)
   @return     GNUTLS_E_SUCCESS on success
*/
int
ecc_mulmod_cached_timing (mpz_t k, gnutls_ecc_curve_t id, ecc_point * R,
                                mpz_t a, mpz_t modulus, int map)
{
  int j, err;

  gnutls_ecc_curve_cache_entry_t *cache = NULL;
  signed char *wmnaf = NULL;
  size_t wmnaf_len;
  signed char digit;
  /* point for throttle */
  ecc_point *T;

  if (k == NULL || R == NULL || modulus == NULL || id == 0)
    return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;

  /* prepare T point */
  T = ecc_new_point ();
  if (T == NULL)
    return GNUTLS_E_MEMORY_ERROR;

  /* calculate wMNAF */
  wmnaf = ecc_wMNAF (k, &wmnaf_len);
  if (!wmnaf)
    {
      err = GNUTLS_E_INTERNAL_ERROR;
      goto done;
    }

  /* set R to neutral */
  mpz_set_ui (R->x, 1);
  mpz_set_ui (R->y, 1);
  mpz_set_ui (R->z, 0);

  /* set T to neutral */
  mpz_set_ui (T->x, 1);
  mpz_set_ui (T->y, 1);
  mpz_set_ui (T->z, 0);

  /* do cache lookup */
  cache = ecc_wmnaf_cache + id - 1;

  /* perform ops */
  for (j = wmnaf_len - 1; j >= 0; --j)
    {
      if ((err = ecc_projective_dbl_point (R, R, a, modulus)) != 0)
        goto done;

      digit = wmnaf[j];

      if (digit)
        {
          if (digit > 0)
            {
              if ((err =
                   ecc_projective_madd (R, cache->pos[(digit / 2)], R, a,
                                        modulus)) != 0)
                goto done;
            }
          else
            {
              if ((err =
                   ecc_projective_madd (R, cache->neg[(-digit / 2)], R, a,
                                        modulus)) != 0)
                goto done;
            }
        }
      else
        {
          /* we add middle element of pos array as a general case
           * there is no real difference between using pos and neg */
          if ((err =
               ecc_projective_madd (R,
                                    cache->
                                    pos[(WMNAF_PRECOMPUTED_LENGTH / 2)], T, a,
                                    modulus)) != 0)
            goto done;
        }
    }


  /* map R back from projective space */
  if (map)
    {
      err = ecc_map (R, modulus);
    }
  else
    {
      err = GNUTLS_E_SUCCESS;
    }
done:
  ecc_del_point (T);
  if (wmnaf)
    free (wmnaf);
  return err;
}
Example #3
0
/*
   Perform a point wMNAF-multiplication utilizing cache
   @param k    The scalar to multiply by
   @param id   The curve's id
   @param R    [out] Destination for kG
   @param a        The curve's A value
   @param modulus  The modulus of the field the ECC curve is in
   @param map      Boolean whether to map back to affine or not (1 == map, 0 == leave in projective)
   @return     GNUTLS_E_SUCCESS on success
*/
int
ecc_mulmod_cached (mpz_t k, gnutls_ecc_curve_t id, ecc_point * R,
                         mpz_t a, mpz_t modulus, int map)
{
  int j, err;

  gnutls_ecc_curve_cache_entry_t *cache = NULL;
  signed char *wmnaf = NULL;
  size_t wmnaf_len;
  signed char digit;

  if (k == NULL || R == NULL || modulus == NULL || id == 0)
    return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;

  /* calculate wMNAF */
  wmnaf = ecc_wMNAF (k, &wmnaf_len);
  if (!wmnaf)
    {
      err = GNUTLS_E_INTERNAL_ERROR;
      goto done;
    }

  /* set R to neutral */
  mpz_set_ui (R->x, 1);
  mpz_set_ui (R->y, 1);
  mpz_set_ui (R->z, 0);

  /* do cache lookup */
  cache = ecc_wmnaf_cache + id - 1;

  /* perform ops */
  for (j = wmnaf_len - 1; j >= 0; --j)
    {
      if ((err = ecc_projective_dbl_point (R, R, a, modulus)) != 0)
        goto done;

      digit = wmnaf[j];

      if (digit)
        {
          if (digit > 0)
            {
              if ((err =
                   ecc_projective_madd (R, cache->pos[(digit / 2)], R, a,
                                        modulus)) != 0)
                goto done;
            }
          else
            {
              if ((err =
                   ecc_projective_madd (R, cache->neg[(-digit / 2)], R, a,
                                        modulus)) != 0)
                goto done;
            }
        }
    }


  /* map R back from projective space */
  if (map)
    {
      err = ecc_map (R, modulus);
    }
  else
    {
      err = GNUTLS_E_SUCCESS;
    }
done:
  if (wmnaf)
    free (wmnaf);
  return err;
}
Example #4
0
/*
   Perform a point multiplication using wMNAF representation
   @param k    The scalar to multiply by
   @param G    The base point
   @param R    [out] Destination for kG
   @param a        The curve's A value
   @param modulus  The modulus of the field the ECC curve is in
   @param map      Boolean whether to map back to affine or not (1 == map, 0 == leave in projective)
   @return     GNUTLS_E_SUCCESS on success
*/
int
ecc_mulmod (mpz_t k, ecc_point * G, ecc_point * R, mpz_t a,
                  mpz_t modulus, int map)
{
  ecc_point *pos[WMNAF_PRECOMPUTED_LENGTH], *neg[WMNAF_PRECOMPUTED_LENGTH];
  int i, j, err;

  signed char *wmnaf = NULL;
  size_t wmnaf_len;
  signed char digit;

  if (k == NULL || G == NULL || R == NULL || modulus == NULL)
    return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;

  /* alloc ram for precomputed values */
  for (i = 0; i < WMNAF_PRECOMPUTED_LENGTH; ++i)
    {
      pos[i] = ecc_new_point ();
      neg[i] = ecc_new_point ();
      if (pos[i] == NULL || neg[i] == NULL)
        {
          for (j = 0; j < i; ++j)
            {
              ecc_del_point (pos[j]);
              ecc_del_point (neg[j]);
            }

          return GNUTLS_E_MEMORY_ERROR;
        }
    }

  /* fill in pos and neg arrays with precomputed values
   * pos holds kG for k ==  1, 3, 5, ..., (2^w - 1)
   * neg holds kG for k == -1,-3,-5, ...,-(2^w - 1)
   */

  /* pos[0] == 2G for a while, later it will be set to the expected 1G */
  if ((err = ecc_projective_dbl_point (G, pos[0], a, modulus)) != 0)
    goto done;

  /* pos[1] == 3G */
  if ((err =
       ecc_projective_add_point (pos[0], G, pos[1], a, modulus)) != 0)
    goto done;

  /* fill in kG for k = 5, 7, ..., (2^w - 1) */
  for (j = 2; j < WMNAF_PRECOMPUTED_LENGTH; ++j)
    {
      if ((err =
           ecc_projective_add_point (pos[j - 1], pos[0], pos[j], a,
                                        modulus)) != 0)
        goto done;
    }

  /* set pos[0] == 1G as expected
   * after this step we don't need G at all 
   * and can change it without worries even if R == G */
  mpz_set (pos[0]->x, G->x);
  mpz_set (pos[0]->y, G->y);
  mpz_set (pos[0]->z, G->z);

  /* neg[i] == -pos[i] */
  for (j = 0; j < WMNAF_PRECOMPUTED_LENGTH; ++j)
    {
      if ((err = ecc_projective_negate_point (pos[j], neg[j], modulus)) != 0)
        goto done;
    }

  /* calculate wMNAF */
  wmnaf = ecc_wMNAF (k, &wmnaf_len);
  if (!wmnaf)
    {
      err = GNUTLS_E_INTERNAL_ERROR;
      goto done;
    }

  /* actual point computation */

  /* set R to neutral */
  mpz_set_ui (R->x, 1);
  mpz_set_ui (R->y, 1);
  mpz_set_ui (R->z, 0);

  /* perform ops */
  for (j = wmnaf_len - 1; j >= 0; --j)
    {
      if ((err = ecc_projective_dbl_point (R, R, a, modulus)) != 0)
        goto done;

      digit = wmnaf[j];

      if (digit)
        {
          if (digit > 0)
            {
              if ((err =
                   ecc_projective_add_point (R, pos[(digit / 2)], R, a,
                                                modulus)) != 0)
                goto done;
            }
          else
            {
              if ((err =
                   ecc_projective_add_point (R, neg[(-digit / 2)], R, a,
                                                modulus)) != 0)
                goto done;
            }
        }
    }


  /* map R back from projective space */
  if (map)
    {
      err = ecc_map (R, modulus);
    }
  else
    {
      err = GNUTLS_E_SUCCESS;
    }
done:
  for (i = 0; i < WMNAF_PRECOMPUTED_LENGTH; ++i)
    {
      ecc_del_point (pos[i]);
      ecc_del_point (neg[i]);
    }
  if (wmnaf)
    free (wmnaf);
  return err;
}
Example #5
0
/**
   Perform a point multiplication 
   @param k    The scalar to multiply by
   @param G    The base point
   @param R    [out] Destination for kG
   @param modulus  The modulus of the field the ECC curve is in
   @param map      Boolean whether to map back to affine or not (1==map, 0 == leave in projective)
   @return CRYPT_OK on success
*/
int
ecc_mulmod (mpz_t k, ecc_point * G, ecc_point * R, mpz_t a, mpz_t modulus,
                int map)

{
   ecc_point *tG, *M[8];
   int        i, j, err, bitidx;
   int        first, bitbuf, bitcpy, mode;

   if (k == NULL || G == NULL || R == NULL || modulus == NULL)
     return -1;

  /* alloc ram for window temps */
  for (i = 0; i < 8; i++) {
      M[i] = ecc_new_point();
      if (M[i] == NULL) {
         for (j = 0; j < i; j++) {
             ecc_del_point(M[j]);
         }

         return -1;
      }
  }

   /* make a copy of G incase R==G */
   tG = ecc_new_point();
   if (tG == NULL)
     { 
       err = -1;
       goto done; 
     }

   /* tG = G  and convert to montgomery */
   mpz_set (tG->x, G->x);
   mpz_set (tG->y, G->y);
   mpz_set (tG->z, G->z);

   /* calc the M tab, which holds kG for k==8..15 */
   /* M[0] == 8G */
   if ((err = ecc_projective_dbl_point (tG, M[0], a, modulus)) != 0)
     goto done;

   if ((err = ecc_projective_dbl_point (M[0], M[0], a, modulus)) != 0)
     goto done;

   if ((err = ecc_projective_dbl_point (M[0], M[0], a, modulus)) != 0)
     goto done;
 
   /* now find (8+k)G for k=1..7 */
   for (j = 9; j < 16; j++) {
     if (ecc_projective_add_point(M[j-9], tG, M[j-8], a, modulus) != 0)
       goto done;
   }

   /* setup sliding window */
   mode   = 0;
   bitidx = mpz_size (k) * GMP_NUMB_BITS - 1;
   bitcpy = bitbuf = 0;
   first  = 1;

   /* perform ops */
   for (;;) {
     /* grab next digit as required */
     if (bitidx == -1) {
       break;
     }

     /* grab the next msb from the ltiplicand */
     i = mpz_tstbit (k, bitidx--);

     /* skip leading zero bits */
     if (mode == 0 && i == 0) {
        continue;
     }

     /* if the bit is zero and mode == 1 then we double */
     if (mode == 1 && i == 0) {
        if ((err = ecc_projective_dbl_point(R, R, a, modulus)) != 0)
          goto done;
        continue;
     }

     /* else we add it to the window */
     bitbuf |= (i << (WINSIZE - ++bitcpy));
     mode = 2;

     if (bitcpy == WINSIZE) {
       /* if this is the first window we do a simple copy */
       if (first == 1) {
          /* R = kG [k = first window] */
          mpz_set(R->x, M[bitbuf-8]->x);
          mpz_set(R->y, M[bitbuf-8]->y);
          mpz_set(R->z, M[bitbuf-8]->z);
          first = 0;
       } else {
         /* normal window */
         /* ok window is filled so double as required and add  */
         /* double first */
         for (j = 0; j < WINSIZE; j++) {
           if ((err = ecc_projective_dbl_point(R, R, a, modulus)) != 0)
             goto done;
         }

         /* then add, bitbuf will be 8..15 [8..2^WINSIZE] guaranteed */
         if ((err = ecc_projective_add_point(R, M[bitbuf-8], R, a, modulus)) != 0)
           goto done;
       }
       /* empty window and reset */
       bitcpy = bitbuf = 0;
       mode = 1;
    }
  }

   /* if bits remain then double/add */
   if (mode == 2 && bitcpy > 0) {
     /* double then add */
     for (j = 0; j < bitcpy; j++) {
       /* only double if we have had at least one add first */
       if (first == 0) {
          if ((err = ecc_projective_dbl_point(R, R, a, modulus)) != 0)
            goto done;
       }

       bitbuf <<= 1;
       if ((bitbuf & (1 << WINSIZE)) != 0) {
         if (first == 1){
            /* first add, so copy */
            mpz_set(R->x, tG->x);
            mpz_set(R->y, tG->y);
            mpz_set(R->z, tG->z);
            first = 0;
         } else {
            /* then add */
            if ((err = ecc_projective_add_point(R, tG, R, a, modulus)) != 0)
              goto done;
         }
       }
     }
   }

   /* map R back from projective space */
   if (map) {
      err = ecc_map(R, modulus);
   } else {
      err = 0;
   }
done:
   ecc_del_point(tG);
   for (i = 0; i < 8; i++) {
       ecc_del_point(M[i]);
   }
   return err;
}
/**
   Verify an ECC signature
   @param sig         The signature to verify
   @param siglen      The length of the signature (octets)
   @param hash        The hash (message digest) that was signed
   @param hashlen     The length of the hash (octets)
   @param stat        Result of signature, 1==valid, 0==invalid
   @param key         The corresponding public ECC key
   @return CRYPT_OK if successful (even if the signature is not valid)
*/
int ecc_verify_hash(const unsigned char *sig,  unsigned long siglen,
                    const unsigned char *hash, unsigned long hashlen, 
                    int *stat, ecc_key *key)
{
   ecc_point    *mG, *mQ;
   mp_int        r, s, v, w, u1, u2, e, p, m;
   mp_digit      mp;
   int           err;

   LTC_ARGCHK(sig  != NULL);
   LTC_ARGCHK(hash != NULL);
   LTC_ARGCHK(stat != NULL);
   LTC_ARGCHK(key  != NULL);

   /* default to invalid signature */
   *stat = 0;

   /* is the IDX valid ?  */
   if (is_valid_idx(key->idx) != 1) {
      return CRYPT_PK_INVALID_TYPE;
   }

   /* allocate ints */
   if ((err = mp_init_multi(&r, &s, &v, &w, &u1, &u2, &p, &e, &m, NULL)) != MP_OKAY) {
      return CRYPT_MEM;
   }

   /* allocate points */
   mG = new_point();
   mQ = new_point();
   if (mQ  == NULL || mG == NULL) {
      err = CRYPT_MEM;
      goto done;
   }

   /* parse header */
   if ((err = der_decode_sequence_multi(sig, siglen,
                                  LTC_ASN1_INTEGER, 1UL, &r,
                                  LTC_ASN1_INTEGER, 1UL, &s,
                                  LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) {
      goto done;
   }

   /* get the order */
   if ((err = mp_read_radix(&p, (char *)sets[key->idx].order, 64)) != MP_OKAY)                  { goto error; }

   /* get the modulus */
   if ((err = mp_read_radix(&m, (char *)sets[key->idx].prime, 64)) != MP_OKAY)                  { goto error; }

   /* check for zero */
   if (mp_iszero(&r) || mp_iszero(&s) || mp_cmp(&r, &p) != MP_LT || mp_cmp(&s, &p) != MP_LT) {
      err = CRYPT_INVALID_PACKET;
      goto done;
   }

   /* read hash */
   if ((err = mp_read_unsigned_bin(&e, (unsigned char *)hash, (int)hashlen)) != MP_OKAY)        { goto error; }

   /*  w  = s^-1 mod n */
   if ((err = mp_invmod(&s, &p, &w)) != MP_OKAY)                                                { goto error; }

   /* u1 = ew */
   if ((err = mp_mulmod(&e, &w, &p, &u1)) != MP_OKAY)                                           { goto error; }

   /* u2 = rw */
   if ((err = mp_mulmod(&r, &w, &p, &u2)) != MP_OKAY)                                           { goto error; }

   /* find mG = u1*G */
   if ((err = mp_read_radix(&mG->x, (char *)sets[key->idx].Gx, 64)) != MP_OKAY)                 { goto error; }
   if ((err = mp_read_radix(&mG->y, (char *)sets[key->idx].Gy, 64)) != MP_OKAY)                 { goto error; }
   mp_set(&mG->z, 1);  
   if ((err = ecc_mulmod(&u1, mG, mG, &m, 0)) != CRYPT_OK)                                      { goto done; }

   /* find mQ = u2*Q */
   if ((err = mp_copy(&key->pubkey.x, &mQ->x)) != MP_OKAY)                                      { goto error; }
   if ((err = mp_copy(&key->pubkey.y, &mQ->y)) != MP_OKAY)                                      { goto error; }
   if ((err = mp_copy(&key->pubkey.z, &mQ->z)) != MP_OKAY)                                      { goto error; }
   if ((err = ecc_mulmod(&u2, mQ, mQ, &m, 0)) != CRYPT_OK)                                      { goto done; }
  
   /* find the montgomery mp */
   if ((err = mp_montgomery_setup(&m, &mp)) != MP_OKAY)                                         { goto error; }
   /* add them */
   if ((err = add_point(mQ, mG, mG, &m, mp)) != CRYPT_OK)                                       { goto done; }
   
   /* reduce */
   if ((err = ecc_map(mG, &m, mp)) != CRYPT_OK)                                                 { goto done; }

   /* v = X_x1 mod n */
   if ((err = mp_mod(&mG->x, &p, &v)) != CRYPT_OK)                                              { goto done; }

   /* does v == r */
   if (mp_cmp(&v, &r) == MP_EQ) {
      *stat = 1;
   }

   /* clear up and return */
   err = CRYPT_OK;
   goto done;
error:
   err = mpi_to_ltc_error(err);
done:
   del_point(mG);
   del_point(mQ);
   mp_clear_multi(&r, &s, &v, &w, &u1, &u2, &p, &e, &m, NULL);
   return err;
}