2 * Copyright (C) 2011-2012 Free Software Foundation, Inc.
4 * Author: Ilya Tumaykin
6 * This file is part of GNUTLS.
8 * The GNUTLS library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 3 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
23 /* needed for gnutls_* types */
24 #include <gnutls_int.h>
25 #include <algorithms.h>
30 /* per-curve cache structure */
34 gnutls_ecc_curve_t id
;
36 /** The array of positive multipliers of G */
37 ecc_point
*pos
[WMNAF_PRECOMPUTED_LENGTH
];
39 /** The array of negative multipliers of G */
40 ecc_point
*neg
[WMNAF_PRECOMPUTED_LENGTH
];
41 } gnutls_ecc_curve_cache_entry_t
;
44 static gnutls_ecc_curve_cache_entry_t
*ecc_wmnaf_cache
= NULL
;
46 /* free single cache entry */
48 _ecc_wmnaf_cache_entry_free (gnutls_ecc_curve_cache_entry_t
* p
)
52 for (i
= 0; i
< WMNAF_PRECOMPUTED_LENGTH
; ++i
)
54 ecc_del_point (p
->pos
[i
]);
55 ecc_del_point (p
->neg
[i
]);
59 /* free curves caches */
61 ecc_wmnaf_cache_free (void)
63 gnutls_ecc_curve_cache_entry_t
*p
= ecc_wmnaf_cache
;
66 for (; p
->id
!= GNUTLS_ECC_CURVE_INVALID
; ++p
)
68 _ecc_wmnaf_cache_entry_free (p
);
71 free (ecc_wmnaf_cache
);
72 ecc_wmnaf_cache
= NULL
;
76 /* initialize single cache entry
77 * for a curve with the given id */
79 _ecc_wmnaf_cache_entry_init (gnutls_ecc_curve_cache_entry_t
* p
,
80 gnutls_ecc_curve_t id
)
86 const gnutls_ecc_curve_entry_st
*st
= NULL
;
88 if (p
== NULL
|| id
== 0)
89 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER
;
94 return GNUTLS_E_MEMORY_ERROR
;
97 st
= _gnutls_ecc_curve_get_params (id
);
100 err
= GNUTLS_E_INTERNAL_ERROR
;
104 if ((err
= mp_init_multi (&a
, &modulus
, NULL
) != 0))
111 mpz_set_str (modulus
, st
->prime
, 16);
113 /* get generator point */
114 mpz_set_str (G
->x
, st
->Gx
, 16);
115 mpz_set_str (G
->y
, st
->Gy
, 16);
116 mpz_set_ui (G
->z
, 1);
119 mpz_set_str (a
, st
->A
, 16);
121 /* alloc ram for precomputed values */
122 for (i
= 0; i
< WMNAF_PRECOMPUTED_LENGTH
; ++i
)
124 p
->pos
[i
] = ecc_new_point ();
125 p
->neg
[i
] = ecc_new_point ();
126 if (p
->pos
[i
] == NULL
|| p
->neg
[i
] == NULL
)
128 for (j
= 0; j
< i
; ++j
)
130 ecc_del_point (p
->pos
[j
]);
131 ecc_del_point (p
->neg
[j
]);
134 err
= GNUTLS_E_MEMORY_ERROR
;
139 /* fill in pos and neg arrays with precomputed values
140 * pos holds kG for k == 1, 3, 5, ..., (2^w - 1)
141 * neg holds kG for k == -1,-3,-5, ...,-(2^w - 1)
144 /* pos[0] == 2G for a while, later it will be set to the expected 1G */
145 if ((err
= ecc_projective_dbl_point (G
, p
->pos
[0], a
, modulus
)) != 0)
150 ecc_projective_add_point (p
->pos
[0], G
, p
->pos
[1], a
,
154 /* fill in kG for k = 5, 7, ..., (2^w - 1) */
155 for (j
= 2; j
< WMNAF_PRECOMPUTED_LENGTH
; ++j
)
158 ecc_projective_add_point (p
->pos
[j
- 1], p
->pos
[0], p
->pos
[j
],
163 /* set pos[0] == 1G as expected
164 * after this step we don't need G at all */
165 mpz_set (p
->pos
[0]->x
, G
->x
);
166 mpz_set (p
->pos
[0]->y
, G
->y
);
167 mpz_set (p
->pos
[0]->z
, G
->z
);
169 /* map to affine all elements in pos
170 * this will allow to use ecc_projective_madd later
171 * set neg[i] == -pos[i] */
172 for (j
= 0; j
< WMNAF_PRECOMPUTED_LENGTH
; ++j
)
174 if ((err
= ecc_map (p
->pos
[j
], modulus
)) != 0)
178 ecc_projective_negate_point (p
->pos
[j
], p
->neg
[j
], modulus
)) != 0)
185 mp_clear_multi (&a
, &modulus
, NULL
);
190 /* initialize curves caches */
192 ecc_wmnaf_cache_init (void)
196 gnutls_ecc_curve_cache_entry_t
*ret
;
198 const gnutls_ecc_curve_t
*p
;
200 ret
= (gnutls_ecc_curve_cache_entry_t
*)
201 malloc (MAX_ALGOS
* sizeof (gnutls_ecc_curve_cache_entry_t
));
203 return GNUTLS_E_MEMORY_ERROR
;
205 /* get supported curves' ids */
206 p
= gnutls_ecc_curve_list ();
208 for (j
= 0; *p
; ++p
, ++j
)
210 if ((err
= _ecc_wmnaf_cache_entry_init (ret
+ *p
- 1, *p
)) != 0)
214 /* nullify last cache entry id */
215 ret
[j
].id
= GNUTLS_ECC_CURVE_INVALID
;
217 err
= GNUTLS_E_SUCCESS
;
219 ecc_wmnaf_cache
= ret
;
224 for (i
= 0; i
< j
; ++i
)
226 _ecc_wmnaf_cache_entry_free (ret
+ i
);
230 ecc_wmnaf_cache
= NULL
;
237 Perform a point wMNAF-multiplication utilizing cache
238 @param k The scalar to multiply by
239 @param id The curve's id
240 @param R [out] Destination for kG
241 @param a The curve's A value
242 @param modulus The modulus of the field the ECC curve is in
243 @param map Boolean whether to map back to affine or not (1 == map, 0 == leave in projective)
244 @return GNUTLS_E_SUCCESS on success
247 ecc_mulmod_cached (mpz_t k
, gnutls_ecc_curve_t id
, ecc_point
* R
,
248 mpz_t a
, mpz_t modulus
, int map
)
252 gnutls_ecc_curve_cache_entry_t
*cache
= NULL
;
253 signed char *wmnaf
= NULL
;
257 if (k
== NULL
|| R
== NULL
|| modulus
== NULL
|| id
== 0)
258 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER
;
260 /* calculate wMNAF */
261 wmnaf
= ecc_wMNAF (k
, &wmnaf_len
);
264 err
= GNUTLS_E_INTERNAL_ERROR
;
268 /* set R to neutral */
269 mpz_set_ui (R
->x
, 1);
270 mpz_set_ui (R
->y
, 1);
271 mpz_set_ui (R
->z
, 0);
273 /* do cache lookup */
274 cache
= ecc_wmnaf_cache
+ id
- 1;
277 for (j
= wmnaf_len
- 1; j
>= 0; --j
)
279 if ((err
= ecc_projective_dbl_point (R
, R
, a
, modulus
)) != 0)
289 ecc_projective_madd (R
, cache
->pos
[(digit
/ 2)], R
, a
,
296 ecc_projective_madd (R
, cache
->neg
[(-digit
/ 2)], R
, a
,
304 /* map R back from projective space */
307 err
= ecc_map (R
, modulus
);
311 err
= GNUTLS_E_SUCCESS
;
320 Perform a point wMNAF-multiplication utilizing cache
321 This version tries to be timing resistant
322 @param k The scalar to multiply by
323 @param id The curve's id
324 @param R [out] Destination for kG
325 @param a The curve's A value
326 @param modulus The modulus of the field the ECC curve is in
327 @param map Boolean whether to map back to affine or not (1 == map, 0 == leave in projective)
328 @return GNUTLS_E_SUCCESS on success
331 ecc_mulmod_cached_timing (mpz_t k
, gnutls_ecc_curve_t id
, ecc_point
* R
,
332 mpz_t a
, mpz_t modulus
, int map
)
336 gnutls_ecc_curve_cache_entry_t
*cache
= NULL
;
337 signed char *wmnaf
= NULL
;
340 /* point for throttle */
343 if (k
== NULL
|| R
== NULL
|| modulus
== NULL
|| id
== 0)
344 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER
;
346 /* prepare T point */
347 T
= ecc_new_point ();
349 return GNUTLS_E_MEMORY_ERROR
;
351 /* calculate wMNAF */
352 wmnaf
= ecc_wMNAF (k
, &wmnaf_len
);
355 err
= GNUTLS_E_INTERNAL_ERROR
;
359 /* set R to neutral */
360 mpz_set_ui (R
->x
, 1);
361 mpz_set_ui (R
->y
, 1);
362 mpz_set_ui (R
->z
, 0);
364 /* set T to neutral */
365 mpz_set_ui (T
->x
, 1);
366 mpz_set_ui (T
->y
, 1);
367 mpz_set_ui (T
->z
, 0);
369 /* do cache lookup */
370 cache
= ecc_wmnaf_cache
+ id
- 1;
373 for (j
= wmnaf_len
- 1; j
>= 0; --j
)
375 if ((err
= ecc_projective_dbl_point (R
, R
, a
, modulus
)) != 0)
385 ecc_projective_madd (R
, cache
->pos
[(digit
/ 2)], R
, a
,
392 ecc_projective_madd (R
, cache
->neg
[(-digit
/ 2)], R
, a
,
399 /* we add middle element of pos array as a general case
400 * there is no real difference between using pos and neg */
402 ecc_projective_madd (R
,
404 pos
[(WMNAF_PRECOMPUTED_LENGTH
/ 2)], T
, a
,
411 /* map R back from projective space */
414 err
= ecc_map (R
, modulus
);
418 err
= GNUTLS_E_SUCCESS
;
428 Perform a point wMNAF-multiplication utilizing cache
429 This function will lookup for an apropriate curve first
430 This function's definition allows in-place substitution instead of ecc_mulmod
431 @param k The scalar to multiply by
432 @param id The curve's id
433 @param R [out] Destination for kG
434 @param a The curve's A value
435 @param modulus The modulus of the field the ECC curve is in
436 @param map Boolean whether to map back to affine or not (1 == map, 0 == leave in projective)
437 @return GNUTLS_E_SUCCESS on success
440 ecc_mulmod_cached_lookup (mpz_t k
, ecc_point
* G
, ecc_point
* R
,
441 mpz_t a
, mpz_t modulus
, int map
)
445 if (k
== NULL
|| G
== NULL
|| R
== NULL
|| modulus
== NULL
)
446 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER
;
448 for (i
= 0; (id
= ecc_wmnaf_cache
[i
].id
); ++i
)
450 if (!(mpz_cmp (G
->x
, ecc_wmnaf_cache
[i
].pos
[0]->x
)) &&
451 !(mpz_cmp (G
->y
, ecc_wmnaf_cache
[i
].pos
[0]->y
)))
457 return ecc_mulmod_cached (k
, id
, R
, a
, modulus
, map
);