Commit | Line | Data |
---|---|---|
432c4e18 | 1 | /* -*-c-*- |
2 | * | |
a69a3efd | 3 | * $Id$ |
432c4e18 | 4 | * |
5 | * Elliptic curve information management | |
6 | * | |
7 | * (c) 2004 Straylight/Edgeware | |
8 | */ | |
9 | ||
45c0fd36 | 10 | /*----- Licensing notice --------------------------------------------------* |
432c4e18 | 11 | * |
12 | * This file is part of Catacomb. | |
13 | * | |
14 | * Catacomb is free software; you can redistribute it and/or modify | |
15 | * it under the terms of the GNU Library General Public License as | |
16 | * published by the Free Software Foundation; either version 2 of the | |
17 | * License, or (at your option) any later version. | |
45c0fd36 | 18 | * |
432c4e18 | 19 | * Catacomb is distributed in the hope that it will be useful, |
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
22 | * GNU Library General Public License for more details. | |
45c0fd36 | 23 | * |
432c4e18 | 24 | * You should have received a copy of the GNU Library General Public |
25 | * License along with Catacomb; if not, write to the Free | |
26 | * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | |
27 | * MA 02111-1307, USA. | |
28 | */ | |
29 | ||
432c4e18 | 30 | /*----- Header files ------------------------------------------------------*/ |
31 | ||
32 | #include "ec.h" | |
33 | #include "ectab.h" | |
34 | #include "gf.h" | |
35 | #include "pgen.h" | |
36 | #include "mprand.h" | |
389d8222 | 37 | #include "mpint.h" |
432c4e18 | 38 | #include "rabin.h" |
39 | ||
40 | /*----- Main code ---------------------------------------------------------*/ | |
41 | ||
42 | /* --- @ec_curveparse@ --- * | |
43 | * | |
44 | * Arguments: @qd_parse *qd@ = parser context | |
45 | * | |
46 | * Returns: Elliptic curve pointer if OK, or null. | |
47 | * | |
48 | * Use: Parses an elliptic curve description, which has the form | |
49 | * | |
50 | * * a field description | |
20095408 | 51 | * * an optional `;' |
432c4e18 | 52 | * * `prime', `primeproj', `bin', or `binproj' |
53 | * * an optional `:' | |
54 | * * the %$a$% parameter | |
55 | * * an optional `,' | |
56 | * * the %$b$% parameter | |
57 | */ | |
58 | ||
59 | ec_curve *ec_curveparse(qd_parse *qd) | |
60 | { | |
61 | mp *a = MP_NEW, *b = MP_NEW; | |
62 | ec_curve *c; | |
63 | field *f; | |
64 | ||
65 | if ((f = field_parse(qd)) == 0) goto fail; | |
20095408 | 66 | qd_delim(qd, ';'); |
432c4e18 | 67 | switch (qd_enum(qd, "prime,primeproj,bin,binproj")) { |
68 | case 0: | |
69 | if (F_TYPE(f) != FTY_PRIME) { | |
70 | qd->e = "field not prime"; | |
71 | goto fail; | |
72 | } | |
73 | qd_delim(qd, ':'); | |
74 | if ((a = qd_getmp(qd)) == 0) goto fail; | |
75 | qd_delim(qd, ','); | |
76 | if ((b = qd_getmp(qd)) == 0) goto fail; | |
77 | c = ec_prime(f, a, b); | |
78 | break; | |
79 | case 1: | |
80 | if (F_TYPE(f) != FTY_PRIME) { | |
81 | qd->e = "field not prime"; | |
82 | goto fail; | |
83 | } | |
84 | qd_delim(qd, ':'); | |
85 | if ((a = qd_getmp(qd)) == 0) goto fail; | |
86 | qd_delim(qd, ','); | |
87 | if ((b = qd_getmp(qd)) == 0) goto fail; | |
88 | c = ec_primeproj(f, a, b); | |
89 | break; | |
90 | case 2: | |
91 | if (F_TYPE(f) != FTY_BINARY) { | |
92 | qd->e = "field not binary"; | |
93 | goto fail; | |
94 | } | |
95 | qd_delim(qd, ':'); | |
96 | if ((a = qd_getmp(qd)) == 0) goto fail; | |
97 | qd_delim(qd, ','); | |
98 | if ((b = qd_getmp(qd)) == 0) goto fail; | |
99 | c = ec_bin(f, a, b); | |
100 | break; | |
101 | case 3: | |
102 | if (F_TYPE(f) != FTY_BINARY) { | |
103 | qd->e = "field not binary"; | |
104 | goto fail; | |
105 | } | |
106 | qd_delim(qd, ':'); | |
107 | if ((a = qd_getmp(qd)) == 0) goto fail; | |
108 | qd_delim(qd, ','); | |
109 | if ((b = qd_getmp(qd)) == 0) goto fail; | |
110 | c = ec_binproj(f, a, b); | |
111 | break; | |
112 | default: | |
113 | goto fail; | |
114 | } | |
02d7884d | 115 | if (!c) { |
116 | qd->e = "bad curve parameters"; | |
117 | goto fail; | |
118 | } | |
432c4e18 | 119 | if (a) MP_DROP(a); |
120 | if (b) MP_DROP(b); | |
121 | return (c); | |
122 | ||
123 | fail: | |
124 | if (f) F_DESTROY(f); | |
125 | if (a) MP_DROP(a); | |
126 | if (b) MP_DROP(b); | |
127 | return (0); | |
128 | } | |
129 | ||
130 | /* --- @ec_ptparse@ --- * | |
131 | * | |
132 | * Arguments: @qd_parse *qd@ = parser context | |
133 | * @ec *p@ = where to put the point | |
134 | * | |
135 | * Returns: The point address, or null. | |
136 | * | |
137 | * Use: Parses an elliptic curve point. This has the form | |
138 | * | |
139 | * * %$x$%-coordinate | |
140 | * * optional `,' | |
141 | * * %$y$%-coordinate | |
142 | */ | |
143 | ||
144 | ec *ec_ptparse(qd_parse *qd, ec *p) | |
145 | { | |
146 | mp *x = MP_NEW, *y = MP_NEW; | |
147 | ||
148 | if (qd_enum(qd, "inf") >= 0) { | |
149 | EC_SETINF(p); | |
150 | return (p); | |
151 | } | |
152 | if ((x = qd_getmp(qd)) == 0) goto fail; | |
153 | qd_delim(qd, ','); | |
154 | if ((y = qd_getmp(qd)) == 0) goto fail; | |
155 | EC_DESTROY(p); | |
156 | p->x = x; | |
157 | p->y = y; | |
158 | p->z = 0; | |
159 | return (p); | |
160 | ||
161 | fail: | |
162 | if (x) MP_DROP(x); | |
163 | if (y) MP_DROP(y); | |
164 | return (0); | |
165 | } | |
166 | ||
20ca05f0 | 167 | /* --- @ec_infofromdata@ --- * |
34e4f738 | 168 | * |
169 | * Arguments: @ec_info *ei@ = where to write the information | |
170 | * @ecdata *ed@ = raw data | |
171 | * | |
172 | * Returns: --- | |
173 | * | |
174 | * Use: Loads elliptic curve information about one of the standard | |
175 | * curves. | |
176 | */ | |
177 | ||
20ca05f0 | 178 | void ec_infofromdata(ec_info *ei, ecdata *ed) |
34e4f738 | 179 | { |
180 | field *f; | |
181 | ||
182 | switch (ed->ftag) { | |
183 | case FTAG_PRIME: | |
184 | f = field_prime(&ed->p); | |
185 | ei->c = ec_primeproj(f, &ed->a, &ed->b); | |
186 | break; | |
187 | case FTAG_NICEPRIME: | |
188 | f = field_niceprime(&ed->p); | |
189 | ei->c = ec_primeproj(f, &ed->a, &ed->b); | |
190 | break; | |
191 | case FTAG_BINPOLY: | |
192 | f = field_binpoly(&ed->p); | |
193 | ei->c = ec_binproj(f, &ed->a, &ed->b); | |
194 | break; | |
4edc47b8 | 195 | case FTAG_BINNORM: |
196 | f = field_binnorm(&ed->p, &ed->beta); | |
197 | ei->c = ec_binproj(f, &ed->a, &ed->b); | |
198 | break; | |
34e4f738 | 199 | default: |
200 | abort(); | |
201 | } | |
202 | ||
02d7884d | 203 | assert(f); assert(ei->c); |
34e4f738 | 204 | EC_CREATE(&ei->g); ei->g.x = &ed->gx; ei->g.y = &ed->gy; ei->g.z = 0; |
205 | ei->r = &ed->r; ei->h = &ed->h; | |
206 | } | |
207 | ||
432c4e18 | 208 | /* --- @ec_infoparse@ --- * |
209 | * | |
210 | * Arguments: @qd_parse *qd@ = parser context | |
211 | * @ec_info *ei@ = curve information block, currently | |
212 | * uninitialized | |
213 | * | |
214 | * Returns: Zero on success, nonzero on failure. | |
215 | * | |
216 | * Use: Parses an elliptic curve information string, and stores the | |
34e4f738 | 217 | * information in @ei@. This is either the name of a standard |
218 | * curve, or it has the form | |
432c4e18 | 219 | * |
220 | * * elliptic curve description | |
20095408 | 221 | * * optional `;' |
432c4e18 | 222 | * * common point |
223 | * * optional `:' | |
224 | * * group order | |
225 | * * optional `*' | |
226 | * * cofactor | |
227 | */ | |
228 | ||
229 | int ec_infoparse(qd_parse *qd, ec_info *ei) | |
230 | { | |
231 | ec_curve *c = 0; | |
232 | field *f; | |
233 | ec g = EC_INIT; | |
34e4f738 | 234 | const ecentry *ee; |
432c4e18 | 235 | mp *r = MP_NEW, *h = MP_NEW; |
236 | ||
20ca05f0 | 237 | for (ee = ectab; ee->name; ee++) { |
238 | if (qd_enum(qd, ee->name) >= 0) { | |
239 | ec_infofromdata(ei, ee->data); | |
240 | goto found; | |
241 | } | |
45c0fd36 | 242 | } |
02d7884d | 243 | |
432c4e18 | 244 | if ((c = ec_curveparse(qd)) == 0) goto fail; |
20095408 | 245 | qd_delim(qd, ';'); if (!ec_ptparse(qd, &g)) goto fail; |
432c4e18 | 246 | qd_delim(qd, ':'); if ((r = qd_getmp(qd)) == 0) goto fail; |
247 | qd_delim(qd, '*'); if ((h = qd_getmp(qd)) == 0) goto fail; | |
432c4e18 | 248 | ei->c = c; ei->g = g; ei->r = r; ei->h = h; |
34e4f738 | 249 | |
250 | found: | |
432c4e18 | 251 | return (0); |
252 | ||
253 | fail: | |
254 | EC_DESTROY(&g); | |
255 | if (r) MP_DROP(r); | |
256 | if (h) MP_DROP(h); | |
257 | if (c) { f = c->f; ec_destroycurve(c); F_DESTROY(f); } | |
258 | return (-1); | |
259 | } | |
260 | ||
432c4e18 | 261 | /* --- @ec_getinfo@ --- * |
262 | * | |
263 | * Arguments: @ec_info *ei@ = where to write the information | |
264 | * @const char *p@ = string describing a curve | |
265 | * | |
266 | * Returns: Null on success, or a pointer to an error message. | |
267 | * | |
268 | * Use: Parses out information about a curve. The string is either a | |
269 | * standard curve name, or a curve info string. | |
270 | */ | |
271 | ||
272 | const char *ec_getinfo(ec_info *ei, const char *p) | |
273 | { | |
274 | qd_parse qd; | |
432c4e18 | 275 | |
276 | qd.p = p; | |
277 | qd.e = 0; | |
432c4e18 | 278 | if (ec_infoparse(&qd, ei)) |
279 | return (qd.e); | |
432c4e18 | 280 | if (!qd_eofp(&qd)) { |
281 | ec_freeinfo(ei); | |
282 | return ("junk found at end of string"); | |
283 | } | |
284 | return (0); | |
285 | } | |
286 | ||
34e4f738 | 287 | /* --- @ec_sameinfop@ --- * |
288 | * | |
289 | * Arguments: @ec_info *ei, *ej@ = two elliptic curve parameter sets | |
290 | * | |
291 | * Returns: Nonzero if the curves are identical (not just isomorphic). | |
292 | * | |
293 | * Use: Checks for sameness of curve parameters. | |
294 | */ | |
295 | ||
296 | int ec_sameinfop(ec_info *ei, ec_info *ej) | |
297 | { | |
298 | return (ec_samep(ei->c, ej->c) && | |
299 | MP_EQ(ei->r, ej->r) && MP_EQ(ei->h, ej->h) && | |
300 | EC_EQ(&ei->g, &ej->g)); | |
301 | } | |
302 | ||
432c4e18 | 303 | /* --- @ec_freeinfo@ --- * |
304 | * | |
305 | * Arguments: @ec_info *ei@ = elliptic curve information block to free | |
306 | * | |
307 | * Returns: --- | |
308 | * | |
309 | * Use: Frees the information block. | |
310 | */ | |
311 | ||
312 | void ec_freeinfo(ec_info *ei) | |
313 | { | |
314 | field *f; | |
315 | ||
316 | EC_DESTROY(&ei->g); | |
317 | MP_DROP(ei->r); | |
318 | MP_DROP(ei->h); | |
319 | f = ei->c->f; ec_destroycurve(ei->c); F_DESTROY(f); | |
320 | } | |
321 | ||
322 | /* --- @ec_checkinfo@ --- * | |
323 | * | |
324 | * Arguments: @const ec_info *ei@ = elliptic curve information block | |
325 | * | |
326 | * Returns: Null if OK, or pointer to error message. | |
327 | * | |
328 | * Use: Checks an elliptic curve according to the rules in SEC1. | |
329 | */ | |
330 | ||
30ac115b | 331 | static const char *gencheck(const ec_info *ei, grand *gr, mp *q) |
432c4e18 | 332 | { |
333 | ec_curve *c = ei->c; | |
334 | field *f = c->f; | |
30ac115b MW |
335 | int i, j, n; |
336 | mp *qq; | |
337 | mp *nn; | |
432c4e18 | 338 | mp *x, *y; |
339 | ec p; | |
340 | int rc; | |
341 | ||
432c4e18 | 342 | /* --- Check %$G \in E$% --- */ |
343 | ||
344 | if (EC_ATINF(&ei->g)) return ("generator at infinity"); | |
345 | if (ec_check(c, &ei->g)) return ("generator not on curve"); | |
346 | ||
347 | /* --- Check %$r$% is prime --- */ | |
348 | ||
34e4f738 | 349 | if (!pgen_primep(ei->r, gr)) return ("generator order not prime"); |
432c4e18 | 350 | |
30ac115b MW |
351 | /* --- Check that the cofactor is correct --- * |
352 | * | |
353 | * Let %$q$% be the size of the field, and let %$n = h r = \#E(\gf{q})$% be | |
354 | * the number of %$\gf{q}$%-rational points on our curve. Hasse's theorem | |
355 | * tells us that | |
356 | * | |
357 | * %$|q + 1 - n| \le 2\sqrt{q}$% | |
358 | * | |
359 | * or, if we square both sides, | |
360 | * | |
361 | * %$(q + 1 - n)^2 \le 4 q$%. | |
362 | * | |
363 | * We'd like the cofactor to be uniquely determined by this equation, which | |
364 | * is possible as long as it's not too big. (If it is, we have to mess | |
365 | * about with Weil pairings, which is no fun.) For this, we need the | |
366 | * following inequalities: | |
367 | * | |
368 | * * %$A = (q + 1 - n)^2 \le 4 q$% (both lower and upper bounds from | |
369 | * Hasse's theorem); | |
432c4e18 | 370 | * |
30ac115b MW |
371 | * * %$B = (q + 1 - n - r)^2 > 4 q$% (check %$h - 1$% isn't possible); |
372 | * and | |
373 | * | |
374 | * * %$C = (q + 1 - n + r)^2 > 4 q$% (check %$h + 1$% isn't possible). | |
432c4e18 | 375 | */ |
376 | ||
30ac115b MW |
377 | rc = 1; |
378 | qq = mp_add(MP_NEW, q, MP_ONE); | |
379 | nn = mp_mul(MP_NEW, ei->r, ei->h); | |
380 | nn = mp_sub(nn, qq, nn); | |
381 | qq = mp_lsl(qq, q, 2); | |
382 | ||
383 | y = mp_sqr(MP_NEW, nn); | |
384 | if (MP_CMP(y, >, qq)) rc = 0; | |
385 | ||
386 | x = mp_sub(MP_NEW, nn, ei->r); | |
387 | y = mp_sqr(y, x); | |
388 | if (MP_CMP(y, <=, qq)) rc = 0; | |
389 | ||
390 | x = mp_add(x, nn, ei->r); | |
391 | y = mp_sqr(y, x); | |
392 | if (MP_CMP(y, <=, qq)) rc = 0; | |
393 | ||
432c4e18 | 394 | MP_DROP(x); |
395 | MP_DROP(y); | |
30ac115b MW |
396 | MP_DROP(nn); |
397 | MP_DROP(qq); | |
398 | if (!rc) return ("incorrect or ambiguous cofactor"); | |
432c4e18 | 399 | |
400 | /* --- Check %$n G = O$% --- */ | |
401 | ||
402 | EC_CREATE(&p); | |
403 | ec_mul(c, &p, &ei->g, ei->r); | |
404 | rc = EC_ATINF(&p); | |
405 | EC_DESTROY(&p); | |
406 | if (!rc) return ("incorrect group order"); | |
407 | ||
30ac115b | 408 | /* --- Check %$q^B \not\equiv 1 \pmod{r}$% for %$1 \le B < 20$% --- * |
432c4e18 | 409 | * |
30ac115b MW |
410 | * Actually, give up if %$q^B \ge 2^{2000}$% because that's probably |
411 | * good enough for jazz. | |
432c4e18 | 412 | */ |
413 | ||
414 | x = MP_NEW; | |
30ac115b MW |
415 | mp_div(0, &x, q, ei->r); |
416 | n = mp_bits(ei->r) - 1; | |
417 | for (i = 0, j = n; i < 20; i++, j += n) { | |
418 | if (j >= 2000) | |
419 | break; | |
420 | if (MP_EQ(x, MP_ONE)) { | |
421 | MP_DROP(x); | |
422 | return("curve embedding degree too low"); | |
423 | } | |
432c4e18 | 424 | x = mp_mul(x, x, f->m); |
425 | mp_div(0, &x, x, ei->r); | |
432c4e18 | 426 | } |
427 | MP_DROP(x); | |
5c3f75ec | 428 | |
432c4e18 | 429 | /* --- Done --- */ |
430 | ||
431 | return (0); | |
432 | } | |
433 | ||
30ac115b MW |
434 | static int primeeltp(mp *x, field *f) |
435 | { return (!MP_NEGP(x) && MP_CMP(x, <, f->m)); } | |
436 | ||
437 | static const char *primecheck(const ec_info *ei, grand *gr) | |
432c4e18 | 438 | { |
439 | ec_curve *c = ei->c; | |
440 | field *f = c->f; | |
432c4e18 | 441 | mp *x, *y; |
432c4e18 | 442 | int rc; |
30ac115b MW |
443 | const char *err; |
444 | ||
445 | /* --- Check %$p$% is an odd prime --- */ | |
446 | ||
447 | if (!pgen_primep(f->m, gr)) return ("p not prime"); | |
448 | ||
449 | /* --- Check %$a$%, %$b$%, %$G_x$% and %$G_y$% are in %$[0, p)$% --- */ | |
450 | ||
451 | if (!primeeltp(c->a, f)) return ("a out of range"); | |
452 | if (!primeeltp(c->b, f)) return ("b out of range"); | |
453 | if (!primeeltp(ei->g.x, f)) return ("G_x out of range"); | |
454 | if (!primeeltp(ei->g.x, f)) return ("G_y out of range"); | |
455 | ||
456 | /* --- Check %$4 a^3 + 27 b^2 \not\equiv 0 \pmod{p}$% --- */ | |
457 | ||
458 | x = F_SQR(f, MP_NEW, c->a); | |
459 | x = F_MUL(f, x, x, c->a); | |
460 | x = F_QDL(f, x, x); | |
461 | y = F_SQR(f, MP_NEW, c->b); | |
462 | y = F_TPL(f, y, y); | |
463 | y = F_TPL(f, y, y); | |
464 | y = F_TPL(f, y, y); | |
465 | x = F_ADD(f, x, x, y); | |
466 | rc = F_ZEROP(f, x); | |
467 | MP_DROP(x); | |
468 | MP_DROP(y); | |
469 | if (rc) return ("not an elliptic curve"); | |
470 | ||
471 | /* --- Now do the general checks --- */ | |
472 | ||
473 | err = gencheck(ei, gr, f->m); | |
474 | return (err); | |
475 | } | |
476 | ||
477 | static const char *bincheck(const ec_info *ei, grand *gr) | |
478 | { | |
479 | ec_curve *c = ei->c; | |
480 | field *f = c->f; | |
481 | mp *x; | |
482 | int rc; | |
483 | const char *err; | |
432c4e18 | 484 | |
389d8222 | 485 | /* --- Check that %$m$% is prime --- */ |
486 | ||
487 | x = mp_fromuint(MP_NEW, f->nbits); | |
488 | rc = pfilt_smallfactor(x); | |
489 | mp_drop(x); | |
490 | if (rc != PGEN_DONE) return ("degree not prime"); | |
491 | ||
432c4e18 | 492 | /* --- Check that %$p$% is irreducible --- */ |
493 | ||
494 | if (!gf_irreduciblep(f->m)) return ("p not irreducible"); | |
495 | ||
496 | /* --- Check that %$a, b, G_x, G_y$% have degree less than %$p$% --- */ | |
497 | ||
498 | if (mp_bits(c->a) > f->nbits) return ("a out of range"); | |
499 | if (mp_bits(c->b) > f->nbits) return ("a out of range"); | |
500 | if (mp_bits(ei->g.x) > f->nbits) return ("G_x out of range"); | |
501 | if (mp_bits(ei->g.y) > f->nbits) return ("G_y out of range"); | |
502 | ||
503 | /* --- Check that %$b \ne 0$% --- */ | |
504 | ||
505 | if (F_ZEROP(f, c->b)) return ("b is zero"); | |
506 | ||
30ac115b | 507 | /* --- Now do the general checks --- */ |
432c4e18 | 508 | |
509 | x = mp_lsl(MP_NEW, MP_ONE, f->nbits); | |
30ac115b MW |
510 | err = gencheck(ei, gr, x); |
511 | mp_drop(x); | |
512 | return (err); | |
432c4e18 | 513 | } |
514 | ||
515 | const char *ec_checkinfo(const ec_info *ei, grand *gr) | |
516 | { | |
517 | switch (F_TYPE(ei->c->f)) { | |
518 | case FTY_PRIME: return (primecheck(ei, gr)); break; | |
519 | case FTY_BINARY: return (bincheck(ei, gr)); break; | |
520 | } | |
521 | return ("unknown curve type"); | |
522 | } | |
523 | ||
524 | /*----- Test rig ----------------------------------------------------------*/ | |
525 | ||
526 | #ifdef TEST_RIG | |
527 | ||
528 | #include "fibrand.h" | |
529 | ||
53cbeae3 | 530 | int main(int argc, char *argv[]) |
432c4e18 | 531 | { |
532 | const ecentry *ee; | |
533 | const char *e; | |
534 | int ok = 1; | |
53cbeae3 | 535 | int i; |
432c4e18 | 536 | grand *gr; |
537 | ||
538 | gr = fibrand_create(0); | |
53cbeae3 | 539 | if (argc > 1) { |
540 | for (i = 1; i < argc; i++) { | |
541 | ec_info ei; | |
542 | if ((e = ec_getinfo(&ei, argv[i])) != 0) | |
543 | fprintf(stderr, "bad curve spec `%s': %s", argv[i], e); | |
544 | else { | |
545 | e = ec_checkinfo(&ei, gr); | |
546 | ec_freeinfo(&ei); | |
547 | if (!e) | |
548 | printf("OK %s\n", argv[i]); | |
549 | else { | |
550 | printf("BAD %s: %s\n", argv[i], e); | |
551 | ok = 0; | |
552 | } | |
553 | } | |
30ac115b | 554 | assert(mparena_count(MPARENA_GLOBAL) == 0); |
53cbeae3 | 555 | } |
556 | } else { | |
20ca05f0 | 557 | fputs("checking standard curves:", stdout); |
558 | fflush(stdout); | |
53cbeae3 | 559 | for (ee = ectab; ee->name; ee++) { |
560 | ec_info ei; | |
20ca05f0 | 561 | ec_infofromdata(&ei, ee->data); |
53cbeae3 | 562 | e = ec_checkinfo(&ei, gr); |
563 | ec_freeinfo(&ei); | |
564 | if (e) { | |
106b481c | 565 | printf(" [%s fails: %s]", ee->name, e); |
53cbeae3 | 566 | ok = 0; |
f94b972d | 567 | } else |
20ca05f0 | 568 | printf(" %s", ee->name); |
53cbeae3 | 569 | fflush(stdout); |
30ac115b | 570 | assert(mparena_count(MPARENA_GLOBAL) == 0); |
432c4e18 | 571 | } |
20ca05f0 | 572 | fputs(ok ? " ok\n" : " failed\n", stdout); |
432c4e18 | 573 | } |
574 | gr->ops->destroy(gr); | |
432c4e18 | 575 | return (!ok); |
576 | } | |
577 | ||
578 | #endif | |
579 | ||
580 | /*----- That's all, folks -------------------------------------------------*/ |