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
);
75 /* initialize single cache entry
76 * for a curve with the given id */
78 _ecc_wmnaf_cache_entry_init (gnutls_ecc_curve_cache_entry_t
* p
,
79 gnutls_ecc_curve_t id
)
85 const gnutls_ecc_curve_entry_st
*st
= NULL
;
87 if (p
== NULL
|| id
== 0)
88 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER
;
93 return GNUTLS_E_MEMORY_ERROR
;
96 st
= _gnutls_ecc_curve_get_params (id
);
99 err
= GNUTLS_E_INTERNAL_ERROR
;
103 if ((err
= mp_init_multi (&a
, &modulus
, NULL
) != 0))
110 mpz_set_str (modulus
, st
->prime
, 16);
112 /* get generator point */
113 mpz_set_str (G
->x
, st
->Gx
, 16);
114 mpz_set_str (G
->y
, st
->Gy
, 16);
115 mpz_set_ui (G
->z
, 1);
118 mpz_set_str (a
, st
->A
, 16);
120 /* alloc ram for precomputed values */
121 for (i
= 0; i
< WMNAF_PRECOMPUTED_LENGTH
; ++i
)
123 p
->pos
[i
] = ecc_new_point ();
124 p
->neg
[i
] = ecc_new_point ();
125 if (p
->pos
[i
] == NULL
|| p
->neg
[i
] == NULL
)
127 for (j
= 0; j
< i
; ++j
)
129 ecc_del_point (p
->pos
[j
]);
130 ecc_del_point (p
->neg
[j
]);
133 err
= GNUTLS_E_MEMORY_ERROR
;
138 /* fill in pos and neg arrays with precomputed values
139 * pos holds kG for k == 1, 3, 5, ..., (2^w - 1)
140 * neg holds kG for k == -1,-3,-5, ...,-(2^w - 1)
143 /* pos[0] == 2G for a while, later it will be set to the expected 1G */
144 if ((err
= ecc_projective_dbl_point (G
, p
->pos
[0], a
, modulus
)) != 0)
149 ecc_projective_add_point (p
->pos
[0], G
, p
->pos
[1], a
,
153 /* fill in kG for k = 5, 7, ..., (2^w - 1) */
154 for (j
= 2; j
< WMNAF_PRECOMPUTED_LENGTH
; ++j
)
157 ecc_projective_add_point (p
->pos
[j
- 1], p
->pos
[0], p
->pos
[j
],
162 /* set pos[0] == 1G as expected
163 * after this step we don't need G at all */
164 mpz_set (p
->pos
[0]->x
, G
->x
);
165 mpz_set (p
->pos
[0]->y
, G
->y
);
166 mpz_set (p
->pos
[0]->z
, G
->z
);
168 /* map to affine all elements in pos
169 * this will allow to use ecc_projective_madd later
170 * set neg[i] == -pos[i] */
171 for (j
= 0; j
< WMNAF_PRECOMPUTED_LENGTH
; ++j
)
173 if ((err
= ecc_map (p
->pos
[j
], modulus
)) != 0)
177 ecc_projective_negate_point (p
->pos
[j
], p
->neg
[j
], modulus
)) != 0)
184 mp_clear_multi (&a
, &modulus
, NULL
);
189 /* initialize curves caches */
191 ecc_wmnaf_cache_init (void)
195 gnutls_ecc_curve_cache_entry_t
*ret
;
197 const gnutls_ecc_curve_t
*p
;
199 ret
= (gnutls_ecc_curve_cache_entry_t
*)
200 malloc (MAX_ALGOS
* sizeof (gnutls_ecc_curve_cache_entry_t
));
202 return GNUTLS_E_MEMORY_ERROR
;
204 /* get supported curves' ids */
205 p
= gnutls_ecc_curve_list ();
207 for (j
= 0; *p
; ++p
, ++j
)
209 if ((err
= _ecc_wmnaf_cache_entry_init (ret
+ *p
- 1, *p
)) != 0)
213 /* nullify last cache entry id */
214 ret
[j
].id
= GNUTLS_ECC_CURVE_INVALID
;
216 err
= GNUTLS_E_SUCCESS
;
218 ecc_wmnaf_cache
= ret
;
223 for (i
= 0; i
< j
; ++i
)
225 _ecc_wmnaf_cache_entry_free (ret
+ i
);
229 ecc_wmnaf_cache
= NULL
;
236 Perform a point wMNAF-multiplication utilizing cache
237 @param k The scalar to multiply by
238 @param id The curve's id
239 @param R [out] Destination for kG
240 @param a The curve's A value
241 @param modulus The modulus of the field the ECC curve is in
242 @param map Boolean whether to map back to affine or not (1 == map, 0 == leave in projective)
243 @return GNUTLS_E_SUCCESS on success
246 ecc_mulmod_cached (mpz_t k
, gnutls_ecc_curve_t id
, ecc_point
* R
,
247 mpz_t a
, mpz_t modulus
, int map
)
251 gnutls_ecc_curve_cache_entry_t
*cache
= NULL
;
252 signed char *wmnaf
= NULL
;
256 if (k
== NULL
|| R
== NULL
|| modulus
== NULL
|| id
== 0)
257 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER
;
259 /* calculate wMNAF */
260 wmnaf
= ecc_wMNAF (k
, &wmnaf_len
);
263 err
= GNUTLS_E_INTERNAL_ERROR
;
267 /* set R to neutral */
268 mpz_set_ui (R
->x
, 1);
269 mpz_set_ui (R
->y
, 1);
270 mpz_set_ui (R
->z
, 0);
272 /* do cache lookup */
273 cache
= ecc_wmnaf_cache
+ id
- 1;
276 for (j
= wmnaf_len
- 1; j
>= 0; --j
)
278 if ((err
= ecc_projective_dbl_point (R
, R
, a
, modulus
)) != 0)
288 ecc_projective_madd (R
, cache
->pos
[(digit
/ 2)], R
, a
,
295 ecc_projective_madd (R
, cache
->neg
[(-digit
/ 2)], R
, a
,
303 /* map R back from projective space */
306 err
= ecc_map (R
, modulus
);
310 err
= GNUTLS_E_SUCCESS
;
319 Perform a point wMNAF-multiplication utilizing cache
320 This version tries to be timing resistant
321 @param k The scalar to multiply by
322 @param id The curve's id
323 @param R [out] Destination for kG
324 @param a The curve's A value
325 @param modulus The modulus of the field the ECC curve is in
326 @param map Boolean whether to map back to affine or not (1 == map, 0 == leave in projective)
327 @return GNUTLS_E_SUCCESS on success
330 ecc_mulmod_cached_timing (mpz_t k
, gnutls_ecc_curve_t id
, ecc_point
* R
,
331 mpz_t a
, mpz_t modulus
, int map
)
335 gnutls_ecc_curve_cache_entry_t
*cache
= NULL
;
336 signed char *wmnaf
= NULL
;
339 /* point for throttle */
342 if (k
== NULL
|| R
== NULL
|| modulus
== NULL
|| id
== 0)
343 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER
;
345 /* prepare T point */
346 T
= ecc_new_point ();
348 return GNUTLS_E_MEMORY_ERROR
;
350 /* calculate wMNAF */
351 wmnaf
= ecc_wMNAF (k
, &wmnaf_len
);
354 err
= GNUTLS_E_INTERNAL_ERROR
;
358 /* set R to neutral */
359 mpz_set_ui (R
->x
, 1);
360 mpz_set_ui (R
->y
, 1);
361 mpz_set_ui (R
->z
, 0);
363 /* set T to neutral */
364 mpz_set_ui (T
->x
, 1);
365 mpz_set_ui (T
->y
, 1);
366 mpz_set_ui (T
->z
, 0);
368 /* do cache lookup */
369 cache
= ecc_wmnaf_cache
+ id
- 1;
372 for (j
= wmnaf_len
- 1; j
>= 0; --j
)
374 if ((err
= ecc_projective_dbl_point (R
, R
, a
, modulus
)) != 0)
384 ecc_projective_madd (R
, cache
->pos
[(digit
/ 2)], R
, a
,
391 ecc_projective_madd (R
, cache
->neg
[(-digit
/ 2)], R
, a
,
398 /* we add middle element of pos array as a general case
399 * there is no real difference between using pos and neg */
401 ecc_projective_madd (R
,
403 pos
[(WMNAF_PRECOMPUTED_LENGTH
/ 2)], T
, a
,
410 /* map R back from projective space */
413 err
= ecc_map (R
, modulus
);
417 err
= GNUTLS_E_SUCCESS
;
427 Perform a point wMNAF-multiplication utilizing cache
428 This function will lookup for an apropriate curve first
429 This function's definition allows in-place substitution instead of ecc_mulmod
430 @param k The scalar to multiply by
431 @param id The curve's id
432 @param R [out] Destination for kG
433 @param a The curve's A value
434 @param modulus The modulus of the field the ECC curve is in
435 @param map Boolean whether to map back to affine or not (1 == map, 0 == leave in projective)
436 @return GNUTLS_E_SUCCESS on success
439 ecc_mulmod_cached_lookup (mpz_t k
, ecc_point
* G
, ecc_point
* R
,
440 mpz_t a
, mpz_t modulus
, int map
)
444 if (k
== NULL
|| G
== NULL
|| R
== NULL
|| modulus
== NULL
)
445 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER
;
447 for (i
= 0; (id
= ecc_wmnaf_cache
[i
].id
); ++i
)
449 if (!(mpz_cmp (G
->x
, ecc_wmnaf_cache
[i
].pos
[0]->x
)) &&
450 !(mpz_cmp (G
->y
, ecc_wmnaf_cache
[i
].pos
[0]->y
)))
456 return ecc_mulmod_cached (k
, id
, R
, a
, modulus
, map
);