3 Copyright (C) 2013 Niels Möller
5 This file is part of GNU Nettle.
7 GNU Nettle is free software: you can redistribute it and/or
8 modify it under the terms of either:
10 * the GNU Lesser General Public License as published by the Free
11 Software Foundation; either version 3 of the License, or (at your
12 option) any later version.
16 * the GNU General Public License as published by the Free
17 Software Foundation; either version 2 of the License, or (at your
18 option) any later version.
20 or both in parallel, as here.
22 GNU Nettle is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 General Public License for more details.
27 You should have received copies of the GNU General Public License and
28 the GNU Lesser General Public License along with this program. If
29 not, see http://www.gnu.org/licenses/.
32 /* Development of Nettle's ECC support was funded by the .SE Internet Fund. */
50 #include "../ecc-internal.h"
51 #include "../gmp-glue.h"
53 #define BENCH_INTERVAL 0.1
55 static void NORETURN PRINTF_STYLE(1,2)
56 die(const char *format, ...)
59 va_start(args, format);
60 vfprintf(stderr, format, args);
69 void *p = malloc (size);
72 fprintf (stderr, "Virtual memory exhausted\n");
79 xalloc_limbs (mp_size_t size)
81 return xalloc (size * sizeof(mp_limb_t));
84 /* Returns second per function call */
86 time_function(void (*f)(void *arg), void *arg)
98 for (i = 0; i < ncalls; i++)
100 elapsed = time_end();
101 if (elapsed > BENCH_INTERVAL)
103 else if (elapsed < BENCH_INTERVAL / 10)
108 return elapsed / ncalls;
111 #if !NETTLE_USE_MINI_GMP
113 modinv_gcd (const struct ecc_curve *ecc,
114 mp_limb_t *rp, mp_limb_t *ap, mp_limb_t *tp)
116 mp_size_t size = ecc->p.size;
118 mp_limb_t *vp = tp + size+1;
119 mp_limb_t *gp = tp + 2*(size+1);
120 mp_limb_t *sp = tp + 3*(size+1);
123 mpn_copyi (up, ap, size);
124 mpn_copyi (vp, ecc->p.m, size);
125 gn = mpn_gcdext (gp, sp, &sn, up, size, vp, size);
126 if (gn != 1 || gp[0] != 1)
130 mpn_sub (sp, ecc->p.m, size, sp, -sn);
133 mpn_zero (sp + sn, size - sn);
135 mpn_copyi (rp, sp, size);
141 const struct ecc_curve *ecc;
151 struct ecc_ctx *ctx = (struct ecc_ctx *) p;
152 mpn_copyi (ctx->rp, ctx->ap, 2*ctx->ecc->p.size);
153 ctx->ecc->p.mod (&ctx->ecc->p, ctx->rp);
157 bench_reduce (void *p)
159 struct ecc_ctx *ctx = (struct ecc_ctx *) p;
160 mpn_copyi (ctx->rp, ctx->ap, 2*ctx->ecc->p.size);
161 ctx->ecc->p.reduce (&ctx->ecc->p, ctx->rp);
167 struct ecc_ctx *ctx = (struct ecc_ctx *) p;
168 mpn_copyi (ctx->rp, ctx->ap, 2*ctx->ecc->p.size);
169 ctx->ecc->q.mod(&ctx->ecc->q, ctx->rp);
173 bench_modinv (void *p)
175 struct ecc_ctx *ctx = (struct ecc_ctx *) p;
176 ctx->ecc->p.invert (&ctx->ecc->p, ctx->rp, ctx->ap, ctx->tp);
179 #if !NETTLE_USE_MINI_GMP
181 bench_modinv_gcd (void *p)
183 struct ecc_ctx *ctx = (struct ecc_ctx *) p;
184 mpn_copyi (ctx->rp + ctx->ecc->p.size, ctx->ap, ctx->ecc->p.size);
185 modinv_gcd (ctx->ecc, ctx->rp, ctx->rp + ctx->ecc->p.size, ctx->tp);
191 bench_modinv_powm (void *p)
193 struct ecc_ctx *ctx = (struct ecc_ctx *) p;
194 const struct ecc_curve *ecc = ctx->ecc;
195 mp_size_t size = ecc->p.size;
197 mpn_sub_1 (ctx->rp + size, ecc->p.m, size, 2);
198 mpn_sec_powm (ctx->rp, ctx->ap, size,
199 ctx->rp + size, ecc->p.bit_size,
200 ecc->p.m, size, ctx->tp);
205 bench_dup_jj (void *p)
207 struct ecc_ctx *ctx = (struct ecc_ctx *) p;
208 ecc_dup_jj (ctx->ecc, ctx->rp, ctx->ap, ctx->tp);
212 bench_add_jja (void *p)
214 struct ecc_ctx *ctx = (struct ecc_ctx *) p;
215 ecc_add_jja (ctx->ecc, ctx->rp, ctx->ap, ctx->bp, ctx->tp);
219 bench_add_hhh (void *p)
221 struct ecc_ctx *ctx = (struct ecc_ctx *) p;
222 ctx->ecc->add_hhh (ctx->ecc, ctx->rp, ctx->ap, ctx->bp, ctx->tp);
226 bench_mul_g (void *p)
228 struct ecc_ctx *ctx = (struct ecc_ctx *) p;
229 ctx->ecc->mul_g (ctx->ecc, ctx->rp, ctx->ap, ctx->tp);
233 bench_mul_a (void *p)
235 struct ecc_ctx *ctx = (struct ecc_ctx *) p;
236 ctx->ecc->mul (ctx->ecc, ctx->rp, ctx->ap, ctx->bp, ctx->tp);
240 bench_dup_eh (void *p)
242 struct ecc_ctx *ctx = (struct ecc_ctx *) p;
243 ecc_dup_eh (ctx->ecc, ctx->rp, ctx->ap, ctx->tp);
247 bench_add_eh (void *p)
249 struct ecc_ctx *ctx = (struct ecc_ctx *) p;
250 ecc_add_eh (ctx->ecc, ctx->rp, ctx->ap, ctx->bp, ctx->tp);
253 #if NETTLE_USE_MINI_GMP
255 mpn_random (mp_limb_t *xp, mp_size_t n)
258 for (i = 0; i < n; i++)
264 bench_curve (const struct ecc_curve *ecc)
267 double modp, reduce, modq, modinv, modinv_gcd, modinv_powm,
268 dup_jj, add_jja, add_hhh,
275 ctx.rp = xalloc_limbs (3*ecc->p.size);
276 ctx.ap = xalloc_limbs (3*ecc->p.size);
277 ctx.bp = xalloc_limbs (3*ecc->p.size);
278 itch = ecc->mul_itch;
282 = mpn_sec_powm_itch (ecc->p.size, ecc->p.bit_size, ecc->p.size);
283 if (powm_itch > itch)
287 ctx.tp = xalloc_limbs (itch);
289 mpn_random (ctx.ap, 3*ecc->p.size);
290 mpn_random (ctx.bp, 3*ecc->p.size);
292 mask = (~(mp_limb_t) 0) >> (ecc->p.size * GMP_NUMB_BITS - ecc->p.bit_size);
293 ctx.ap[ecc->p.size - 1] &= mask;
294 ctx.ap[2*ecc->p.size - 1] &= mask;
295 ctx.ap[3*ecc->p.size - 1] &= mask;
296 ctx.bp[ecc->p.size - 1] &= mask;
297 ctx.bp[2*ecc->p.size - 1] &= mask;
298 ctx.bp[3*ecc->p.size - 1] &= mask;
300 modp = time_function (bench_modp, &ctx);
301 reduce = time_function (bench_reduce, &ctx);
303 modq = time_function (bench_modq, &ctx);
305 modinv = time_function (bench_modinv, &ctx);
306 #if !NETTLE_USE_MINI_GMP
307 modinv_gcd = time_function (bench_modinv_gcd, &ctx);
312 modinv_powm = time_function (bench_modinv_powm, &ctx);
316 if (ecc->p.bit_size == 255)
318 /* For now, curve25519 is a special case */
319 dup_jj = time_function (bench_dup_eh, &ctx);
320 add_jja = time_function (bench_add_eh, &ctx);
324 dup_jj = time_function (bench_dup_jj, &ctx);
325 add_jja = time_function (bench_add_jja, &ctx);
327 add_hhh = time_function (bench_add_hhh, &ctx);
328 mul_g = time_function (bench_mul_g, &ctx);
329 mul_a = time_function (bench_mul_a, &ctx);
336 printf ("%4d %6.4f %6.4f %6.4f %6.2f %6.3f %6.2f %6.3f %6.3f %6.3f %6.1f %6.1f\n",
337 ecc->p.bit_size, 1e6 * modp, 1e6 * reduce, 1e6 * modq,
338 1e6 * modinv, 1e6 * modinv_gcd, 1e6 * modinv_powm,
339 1e6 * dup_jj, 1e6 * add_jja, 1e6 * add_hhh,
340 1e6 * mul_g, 1e6 * mul_a);
343 const struct ecc_curve * const curves[] = {
352 #define numberof(x) (sizeof (x) / sizeof ((x)[0]))
355 main (int argc UNUSED, char **argv UNUSED)
360 printf ("%4s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s (us)\n",
361 "size", "modp", "reduce", "modq", "modinv", "mi_gcd", "mi_pow",
362 "dup_jj", "ad_jja", "ad_hhh",
364 for (i = 0; i < numberof (curves); i++)
365 bench_curve (curves[i]);