/*
   Add two ECC points
   @param P        The point to add
   @param Q        The point to add
   @param R        [out] The destination of the double
   @param a        Curve's a value
   @param modulus  The modulus of the field the ECC curve is in
   @return         GNUTLS_E_SUCCESS on success
*/
int
ecc_projective_add_point (ecc_point * P, ecc_point * Q, ecc_point * R,
                              mpz_t a, mpz_t modulus)
{
  /* Using "(m)add-2004-hmv" algorithm
   * It costs 12M + 4S + half. */
  mpz_t t1, t2, x, y, z;
  int err;

  if (P == NULL || Q == NULL || R == NULL || modulus == NULL)
    return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;

  /* check for neutral points */
  if ( (err = ecc_projective_isneutral(Q, modulus)) == 0 ) {
    /* P + Q = P + neutral = P */

    mpz_set (R->x, P->x);
    mpz_set (R->y, P->y);
    mpz_set (R->z, P->z);

    return GNUTLS_E_SUCCESS;
  } else if (err < 0) {
    return err;
  }

  if ( (err = ecc_projective_isneutral(P, modulus)) == 0 ) {
    /* P + Q = neutral + Q = Q */

    mpz_set (R->x, Q->x);
    mpz_set (R->y, Q->y);
    mpz_set (R->z, Q->z);

    return GNUTLS_E_SUCCESS;
  } else if (err < 0) {
    return err;
  }

  if ((err = mp_init_multi (&t1, &t2, &x, &y, &z, NULL)) != 0)
    {
      return err;
    }

  /* Check if P == Q and do doubling in that case
   * If Q == -P then P + Q = neutral element
   */
  if ((mpz_cmp (P->x, Q->x) == 0) &&
      (mpz_cmp (P->z, Q->z) == 0))
    {
      /* x and z coordinates match. Check if P->y = Q->y, or P->y = -Q->y
       */
      if (mpz_cmp (P->y, Q->y) == 0)
        {
          mp_clear_multi (&t1, &t2, &x, &y, &z, NULL);
          return ecc_projective_dbl_point (P, R, a, modulus);
        }

      mpz_sub (t1, modulus, Q->y);
      if (mpz_cmp (P->y, t1) == 0)
        {
          mp_clear_multi (&t1, &t2, &x, &y, &z, NULL);
          mpz_set_ui(R->x, 1);
          mpz_set_ui(R->y, 1);
          mpz_set_ui(R->z, 0);
          return GNUTLS_E_SUCCESS;
        }
    }


  mpz_set (x, P->x);
  mpz_set (y, P->y);
  mpz_set (z, P->z);

  /* if Z is one then these are no-operations */
  if (mpz_cmp_ui (Q->z, 1) != 0)
    {
      /* T1 = Z' * Z' */
      mpz_mul (t1, Q->z, Q->z);
      mpz_mod (t1, t1, modulus);
      /* X = X * T1 */
      mpz_mul (x, x, t1);
      mpz_mod (x, x, modulus);
      /* T1 = Z' * T1 */
      mpz_mul (t1, t1, Q->z);
      mpz_mod (t1, t1, modulus);
      /* Y = Y * T1 */
      mpz_mul (y, y, t1);
      mpz_mod (y, y, modulus);
    }

  /* T1 = Z*Z */
  mpz_mul (t1, z, z);
  mpz_mod (t1, t1, modulus);
  /* T2 = X' * T1 */
  mpz_mul (t2, t1, Q->x);
  mpz_mod (t2, t2, modulus);
  /* T1 = Z * T1 */
  mpz_mul (t1, t1, z);
  mpz_mod (t1, t1, modulus);
  /* T1 = Y' * T1 */
  mpz_mul (t1, t1, Q->y);
  mpz_mod (t1, t1, modulus);

  /* Y = Y - T1 */
  mpz_sub (y, y, t1);
  if (mpz_cmp_ui (y, 0) < 0)
    {
      mpz_add (y, y, modulus);
    }
  /* T1 = 2T1 */
  mpz_add (t1, t1, t1);
  if (mpz_cmp (t1, modulus) >= 0)
    {
      mpz_sub (t1, t1, modulus);
    }
  /* T1 = Y + T1 */
  mpz_add (t1, t1, y);
  if (mpz_cmp (t1, modulus) >= 0)
    {
      mpz_sub (t1, t1, modulus);
    }
  /* X = X - T2 */
  mpz_sub (x, x, t2);
  if (mpz_cmp_ui (x, 0) < 0)
    {
      mpz_add (x, x, modulus);
    }
  /* T2 = 2T2 */
  mpz_add (t2, t2, t2);
  if (mpz_cmp (t2, modulus) >= 0)
    {
      mpz_sub (t2, t2, modulus);
    }
  /* T2 = X + T2 */
  mpz_add (t2, t2, x);
  if (mpz_cmp (t2, modulus) >= 0)
    {
      mpz_sub (t2, t2, modulus);
    }

  /* if Z' != 1 */
  if (mpz_cmp_ui (Q->z, 1) != 0)
    {
      /* Z = Z * Z' */
      mpz_mul (z, z, Q->z);
      mpz_mod (z, z, modulus);
    }

  /* Z = Z * X */
  mpz_mul (z, z, x);
  mpz_mod (z, z, modulus);

  /* T1 = T1 * X  */
  mpz_mul (t1, t1, x);
  mpz_mod (t1, t1, modulus);
  /* X = X * X */
  mpz_mul (x, x, x);
  mpz_mod (x, x, modulus);
  /* T2 = T2 * x */
  mpz_mul (t2, t2, x);
  mpz_mod (t2, t2, modulus);
  /* T1 = T1 * X  */
  mpz_mul (t1, t1, x);
  mpz_mod (t1, t1, modulus);

  /* X = Y*Y */
  mpz_mul (x, y, y);
  mpz_mod (x, x, modulus);
  /* X = X - T2 */
  mpz_sub (x, x, t2);
  if (mpz_cmp_ui (x, 0) < 0)
    {
      mpz_add (x, x, modulus);
    }

  /* T2 = T2 - X */
  mpz_sub (t2, t2, x);
  if (mpz_cmp_ui (t2, 0) < 0)
    {
      mpz_add (t2, t2, modulus);
    }
  /* T2 = T2 - X */
  mpz_sub (t2, t2, x);
  if (mpz_cmp_ui (t2, 0) < 0)
    {
      mpz_add (t2, t2, modulus);
    }
  /* T2 = T2 * Y */
  mpz_mul (t2, t2, y);
  mpz_mod (t2, t2, modulus);
  /* Y = T2 - T1 */
  mpz_sub (y, t2, t1);
  if (mpz_cmp_ui (y, 0) < 0)
    {
      mpz_add (y, y, modulus);
    }
  /* Y = Y/2 */
  if (mpz_odd_p (y))
    {
      mpz_add (y, y, modulus);
    }
  mpz_divexact_ui (y, y, 2);

  mpz_set (R->x, x);
  mpz_set (R->y, y);
  mpz_set (R->z, z);

  err = GNUTLS_E_SUCCESS;

  mp_clear_multi (&t1, &t2, &x, &y, &z, NULL);
  return err;
}
/*
   Add two ECC points
   @param P        The point to add
   @param Q        The point to add
   @param R        [out] The destination of the double
   @param a        Curve's a value
   @param modulus  The modulus of the field the ECC curve is in
   @return 0 on success
*/
int
ecc_projective_add_point (ecc_point * P, ecc_point * Q, ecc_point * R,
                              mpz_t a, mpz_t modulus)
{
  mpz_t t1, t2, x, y, z;
  int err;

  if (P == NULL || Q == NULL || R == NULL || modulus == NULL)
    return -1;

  if ((err = mp_init_multi (&t1, &t2, &x, &y, &z, NULL)) != 0)
    {
      return err;
    }

  /* Check if P == Q and do doubling in that case 
   * If Q == -P then P+Q=point at infinity
   */
  if ((mpz_cmp (P->x, Q->x) == 0) &&
      (mpz_cmp (P->z, Q->z) == 0))
    {
      /* x and z coordinates match. Check if P->y = Q->y, or P->y = -Q->y
       */
      if (mpz_cmp (P->y, Q->y) == 0)
        {
          mp_clear_multi (&t1, &t2, &x, &y, &z, NULL);
          return ecc_projective_dbl_point (P, R, a, modulus);
        }
      
      mpz_sub (t1, modulus, Q->y);
      if (mpz_cmp (P->y, t1) == 0)
        {
          mp_clear_multi (&t1, &t2, &x, &y, &z, NULL);
          mpz_set_ui(R->x, 1);
          mpz_set_ui(R->y, 1);
          mpz_set_ui(R->z, 0);
          return 0;
        }
    }


  mpz_set (x, P->x);
  mpz_set (y, P->y);
  mpz_set (z, P->z);

  /* if Z is one then these are no-operations */
  if (mpz_cmp_ui (Q->z, 1) != 0)
    {
      /* T1 = Z' * Z' */
      mpz_mul (t1, Q->z, Q->z);
      mpz_mod (t1, t1, modulus);
      /* X = X * T1 */
      mpz_mul (x, x, t1);
      mpz_mod (x, x, modulus);
      /* T1 = Z' * T1 */
      mpz_mul (t1, t1, Q->z);
      mpz_mod (t1, t1, modulus);
      /* Y = Y * T1 */
      mpz_mul (y, y, t1);
      mpz_mod (y, y, modulus);
    }

  /* T1 = Z*Z */
  mpz_mul (t1, z, z);
  mpz_mod (t1, t1, modulus);
  /* T2 = X' * T1 */
  mpz_mul (t2, t1, Q->x);
  mpz_mod (t2, t2, modulus);
  /* T1 = Z * T1 */
  mpz_mul (t1, t1, z);
  mpz_mod (t1, t1, modulus);
  /* T1 = Y' * T1 */
  mpz_mul (t1, t1, Q->y);
  mpz_mod (t1, t1, modulus);

  /* Y = Y - T1 */
  mpz_sub (y, y, t1);
  if (mpz_cmp_ui (y, 0) < 0)
    {
      mpz_add (y, y, modulus);
    }
  /* T1 = 2T1 */
  mpz_add (t1, t1, t1);
  if (mpz_cmp (t1, modulus) >= 0)
    {
      mpz_sub (t1, t1, modulus);
    }
  /* T1 = Y + T1 */
  mpz_add (t1, t1, y);
  if (mpz_cmp (t1, modulus) >= 0)
    {
      mpz_sub (t1, t1, modulus);
    }
  /* X = X - T2 */
  mpz_sub (x, x, t2);
  if (mpz_cmp_ui (x, 0) < 0)
    {
      mpz_add (x, x, modulus);
    }
  /* T2 = 2T2 */
  mpz_add (t2, t2, t2);
  if (mpz_cmp (t2, modulus) >= 0)
    {
      mpz_sub (t2, t2, modulus);
    }
  /* T2 = X + T2 */
  mpz_add (t2, t2, x);
  if (mpz_cmp (t2, modulus) >= 0)
    {
      mpz_sub (t2, t2, modulus);
    }

  /* if Z' != 1 */
  if (mpz_cmp_ui (Q->z, 1) != 0)
    {
      /* Z = Z * Z' */
      mpz_mul (z, z, Q->z);
      mpz_mod (z, z, modulus);
    }

  /* Z = Z * X */
  mpz_mul (z, z, x);
  mpz_mod (z, z, modulus);

  /* T1 = T1 * X  */
  mpz_mul (t1, t1, x);
  mpz_mod (t1, t1, modulus);
  /* X = X * X */
  mpz_mul (x, x, x);
  mpz_mod (x, x, modulus);
  /* T2 = T2 * x */
  mpz_mul (t2, t2, x);
  mpz_mod (t2, t2, modulus);
  /* T1 = T1 * X  */
  mpz_mul (t1, t1, x);
  mpz_mod (t1, t1, modulus);

  /* X = Y*Y */
  mpz_mul (x, y, y);
  mpz_mod (x, x, modulus);
  /* X = X - T2 */
  mpz_sub (x, x, t2);
  if (mpz_cmp_ui (x, 0) < 0)
    {
      mpz_add (x, x, modulus);
    }

  /* T2 = T2 - X */
  mpz_sub (t2, t2, x);
  if (mpz_cmp_ui (t2, 0) < 0)
    {
      mpz_add (t2, t2, modulus);
    }
  /* T2 = T2 - X */
  mpz_sub (t2, t2, x);
  if (mpz_cmp_ui (t2, 0) < 0)
    {
      mpz_add (t2, t2, modulus);
    }
  /* T2 = T2 * Y */
  mpz_mul (t2, t2, y);
  mpz_mod (t2, t2, modulus);
  /* Y = T2 - T1 */
  mpz_sub (y, t2, t1);
  if (mpz_cmp_ui (y, 0) < 0)
    {
      mpz_add (y, y, modulus);
    }
  /* Y = Y/2 */
  if (mpz_odd_p (y))
    {
      mpz_add (y, y, modulus);
    }
  mpz_divexact_ui (y, y, 2);

  mpz_set (R->x, x);
  mpz_set (R->y, y);
  mpz_set (R->z, z);

  err = 0;

  mp_clear_multi (&t1, &t2, &x, &y, &z, NULL);
  return err;
}
Example #3
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 #4
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 #5
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 #6
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 #7
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;
}