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