chiark / gitweb /
Upgrade licence to GPLv3+.
[tripe] / server / dh.c
1 /* -*-c-*-
2  *
3  * Diffie--Hellman groups
4  *
5  * (c) 2017 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of Trivial IP Encryption (TrIPE).
11  *
12  * TrIPE is free software: you can redistribute it and/or modify it under
13  * the terms of the GNU General Public License as published by the Free
14  * Software Foundation; either version 3 of the License, or (at your
15  * option) any later version.
16  *
17  * TrIPE is distributed in the hope that it will be useful, but WITHOUT
18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20  * for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with TrIPE.  If not, see <https://www.gnu.org/licenses/>.
24  */
25
26 /*----- Header files ------------------------------------------------------*/
27
28 #include "tripe.h"
29
30 /*----- Common utilities --------------------------------------------------*/
31
32 /* --- @KLOAD@ --- *
33  *
34  * Arguments:   @pre@ = prefix for defined functions
35  *              @ty@, @TY@ = key type name (lower- and upper-case)
36  *              @setgroup@ = code to initialize @kd->g@
37  *              @setpriv@ = code to initialize @kd->kpriv@
38  *              @setpub@ = code to initialize @kd->kpub@
39  *
40  * Use:         Generates the body of one of the (rather tedious) key loading
41  *              functions.  See the description of @KEYTYPES@ below for the
42  *              details.
43  */
44
45 #define KLOAD_HALF(pre, ty, TY, which, WHICH, setgroup, setpriv, setpub) \
46 static int pre##_ld##which(key_file *kf, key *k, key_data *d,           \
47                            kdata *kd, dstr *t, dstr *e)                 \
48 {                                                                       \
49   key_packstruct kps[TY##_##WHICH##FETCHSZ];                            \
50   key_packdef *kp;                                                      \
51   ty##_##which p;                                                       \
52   int rc;                                                               \
53                                                                         \
54   /* --- Initialize things we've not set up yet --- */                  \
55                                                                         \
56   kd->grp = 0; kd->k = 0; kd->K = 0;                                    \
57                                                                         \
58   /* --- Unpack the key --- */                                          \
59                                                                         \
60   kp = key_fetchinit(ty##_##which##fetch, kps, &p);                     \
61   if ((rc = key_unpack(kp, d, t)) != 0) {                               \
62     a_format(e, "unpack-failed", "%s", key_strerror(rc), A_END);        \
63     goto fail;                                                          \
64   }                                                                     \
65                                                                         \
66   /* --- Extract the pieces of the key --- */                           \
67                                                                         \
68   setgroup;                                                             \
69   setpriv;                                                              \
70   setpub;                                                               \
71                                                                         \
72   /* --- We win --- */                                                  \
73                                                                         \
74   rc = 0;                                                               \
75   goto done;                                                            \
76                                                                         \
77 fail:                                                                   \
78   if (kd->grp) {                                                        \
79     if (kd->K) pre##_freege(kd->grp, kd->K);                            \
80     if (kd->k) pre##_freesc(kd->grp, kd->k);                            \
81     pre##_freegrp(kd->grp);                                             \
82   }                                                                     \
83   rc = -1;                                                              \
84                                                                         \
85 done:                                                                   \
86   key_fetchdone(kp);                                                    \
87   return (rc);                                                          \
88 }
89
90 #define KLOAD(pre, ty, TY, setgroup, setpriv, setpub)                   \
91 static void pre##_freegrp(dhgrp *); \
92 static void pre##_freesc(const dhgrp *, dhsc *); \
93 static void pre##_freege(const dhgrp *, dhge *); \
94   KLOAD_HALF(pre, ty, TY, priv, PRIV, setgroup, setpriv, setpub)        \
95   KLOAD_HALF(pre, ty, TY, pub, PUB, setgroup, { kd->k = 0; }, setpub)
96
97 enum { DHSER_V0, DHSER_CONSTLEN };
98
99 static int get_serialization(key_file *kf, key *k, dstr *e)
100 {
101   const char *p = key_getattr(kf, k, "serialization");
102   if (!p || strcmp(p, "v0") == 0) return (DHSER_V0);
103   else if (strcmp(p, "constlen") == 0) return (DHSER_CONSTLEN);
104   else {
105     a_format(e, "unknown-serialization-format", "%s", p, A_END);
106     return (-1);
107   }
108 }
109
110 #ifndef NTRACE
111 static void setupstr(mptext_stringctx *sc)
112   { sc->buf = (char *)buf_u; sc->lim = sc->buf + sizeof(buf_u); }
113
114 static const char *donestr(mptext_stringctx *sc)
115   { *sc->buf = 0; return ((const char *)buf_u); }
116
117 static void addlitstr(const char *p, mptext_stringctx *sc)
118   { mptext_stringops.put(p, strlen(p), sc); }
119
120 static void addmpstr(mp *x, int radix, mptext_stringctx *sc)
121 {
122   char b[12];
123
124   if (radix == 16) addlitstr("0x", sc);
125   else if (radix == 8) addlitstr("0", sc);
126   else if (radix != 10) { sprintf(b, "%d#", radix); addlitstr(b, sc); }
127   mp_write(x, radix, &mptext_stringops, sc);
128 }
129
130 static const char *mpstr(mp *x, int radix)
131 {
132   mptext_stringctx sc;
133
134   setupstr(&sc);
135   addmpstr(x, radix, &sc);
136   return (donestr(&sc));
137 }
138 #endif
139
140 /*----- Schnorr groups ----------------------------------------------------*/
141
142 typedef struct intdh_grp {
143   dhgrp _g;
144   mpmont mm;
145   mp *q, *G;
146   size_t gesz;
147   int ser;
148 } intdh_grp;
149
150 typedef struct intdh_sc { mp *x; } intdh_sc;
151 typedef struct intdh_ge { mp *X; } intdh_ge;
152
153 static dhgrp *intdh_mkgroup(key_file *kf, key *k,
154                             const dh_param *dp, dstr *e)
155 {
156   intdh_grp *g;
157   int ser;
158
159   if ((ser = get_serialization(kf, k, e)) < 0) return (0);
160   g = CREATE(intdh_grp);
161   g->ser = ser;
162   g->_g.scsz = mp_octets(dp->q);
163   g->gesz = mp_octets(dp->p);
164   mpmont_create(&g->mm, dp->p);
165   g->q = MP_COPY(dp->q);
166   g->G = mpmont_mul(&g->mm, MP_NEW, dp->g, g->mm.r2);
167   return (&g->_g);
168 }
169
170 static dhsc *intdh_mptosc(const dhgrp *gg, mp *z)
171 {
172   const intdh_grp *g = (const intdh_grp *)gg;
173   intdh_sc *x = CREATE(intdh_sc);
174   x->x = MP_NEW; mp_div(0, &x->x, z, g->q);
175   return ((dhsc *)x);
176 }
177
178 static dhge *intdh_mptoge(const dhgrp *gg, mp *z)
179 {
180   const intdh_grp *g = (const intdh_grp *)gg;
181   intdh_ge *Y = CREATE(intdh_ge);
182   mp *t = MP_NEW; mp_div(0, &t, z, g->mm.m);
183   Y->X = mpmont_mul(&g->mm, t, t, g->mm.r2);
184   return ((dhge *)Y);
185 }
186
187 KLOAD(intdh, dh, DH,
188       { if ((kd->grp = intdh_mkgroup(kf, k, &p.dp, e)) == 0) goto fail; },
189       { kd->k = intdh_mptosc(kd->grp, p.x); },
190       { kd->K = intdh_mptoge(kd->grp, p.y); })
191
192 static const char *intdh_checkgrp(const dhgrp *gg)
193 {
194   const intdh_grp *g = (const intdh_grp *)gg;
195   mp *t = MP_NEW;
196
197   if (!pgen_primep(g->mm.m, &rand_global)) return ("p is not prime");
198   if (!pgen_primep(g->q, &rand_global)) return ("q is not prime");
199   mp_div(0, &t, g->mm.m, g->q);
200   if (!MP_EQ(t, MP_ONE)) return ("q is not a subgroup order");
201   t = mpmont_expr(&g->mm, t, g->G, g->q);
202   if (!MP_EQ(t, g->mm.r)) return ("g not in the subgroup");
203   return (0);
204 }
205
206 static void intdh_grpinfo(const dhgrp *gg, admin *adm)
207 {
208   const intdh_grp *g = (const intdh_grp *)gg;
209   a_info(adm,
210          "kx-group=prime",
211          "kx-group-order-bits=%lu", (unsigned long)mp_bits(g->q),
212          "kx-group-elt-bits=%lu", (unsigned long)mp_bits(g->mm.m),
213          A_END);
214 }
215
216 #ifndef NTRACE
217 static void intdh_tracegrp(const dhgrp *gg)
218 {
219   const intdh_grp *g = (const intdh_grp *)gg;
220   mp *t = MP_NEW;
221   trace(T_CRYPTO, "crypto: group type `dh'");
222   trace(T_CRYPTO, "crypto: p = %s", mpstr(g->mm.m, 10));
223   trace(T_CRYPTO, "crypto: q = %s", mpstr(g->q, 10));
224   t = mpmont_reduce(&g->mm, t, g->G);
225   trace(T_CRYPTO, "crypto: g = %s", mpstr(t, 10));
226   MP_DROP(t);
227 }
228 #endif
229
230 static int intdh_samegrpp(const dhgrp *gg, const dhgrp *hh)
231 {
232   const intdh_grp *g = (const intdh_grp *)gg, *h = (const intdh_grp *)hh;
233   return (MP_EQ(g->mm.m, h->mm.m) &&
234           MP_EQ(g->q, h->q) && MP_EQ(g->G, h->G) &&
235           g->ser == h->ser);
236 }
237
238 static void intdh_freegrp(dhgrp *gg)
239 {
240   intdh_grp *g = (intdh_grp *)gg;
241   mpmont_destroy(&g->mm); MP_DROP(g->q); MP_DROP(g->G);
242   DESTROY(g);
243 }
244
245 static dhsc *intdh_ldsc(const dhgrp *gg, const void *p, size_t sz)
246 { const intdh_grp *g = (const intdh_grp *)gg;
247   intdh_sc *x = CREATE(intdh_sc);
248   mp *t = mp_loadb(MP_NEW, p, sz);
249   mp_div(0, &t, t, g->q); x->x = t;
250   return ((dhsc *)x);
251 }
252
253 static int intdh_stsc(const dhgrp *gg, void *p, size_t sz, const dhsc *xx)
254 {
255   const intdh_sc *x = (const intdh_sc *)xx;
256   mp_storeb(x->x, p, sz);
257   return (0);
258 }
259
260 static dhsc *intdh_randsc(const dhgrp *gg)
261 {
262   const intdh_grp *g = (const intdh_grp *)gg;
263   intdh_sc *x = CREATE(intdh_sc);
264   x->x = mprand_range(MP_NEW, g->q, &rand_global, 0);
265   return ((dhsc *)x);
266 }
267
268 #ifndef NTRACE
269 static const char *intdh_scstr(const dhgrp *gg, const dhsc *xx)
270   { const intdh_sc *x = (const intdh_sc *)xx; return (mpstr(x->x, 10)); }
271 #endif
272
273 static void intdh_freesc(const dhgrp *gg, dhsc *xx)
274 {
275   intdh_sc *x = (intdh_sc *)xx;
276   MP_DROP(x->x); DESTROY(x);
277 }
278
279 static dhge *intdh_ldge(const dhgrp *gg, buf *b, int fmt)
280 {
281   const intdh_grp *g = (const intdh_grp *)gg;
282   intdh_ge *Y;
283   mp *t;
284   const octet *p;
285
286   switch (fmt) {
287     case DHFMT_HASH: if (g->ser == DHSER_CONSTLEN) goto std;
288     case DHFMT_VAR:
289       if ((t = buf_getmp(b)) == 0) return (0);
290       break;
291     case DHFMT_STD: std:
292       if ((p = buf_get(b, g->gesz)) == 0) return (0);
293       t = mp_loadb(MP_NEW, p, g->gesz);
294       break;
295     default:
296       abort();
297   }
298   Y = CREATE(intdh_ge);
299   mp_div(0, &t, t, g->mm.m);
300   Y->X = mpmont_mul(&g->mm, t, t, g->mm.r2);
301   return ((dhge *)Y);
302 }
303
304 static int intdh_stge(const dhgrp *gg, buf *b, const dhge *YY, int fmt)
305 {
306   const intdh_grp *g = (const intdh_grp *)gg;
307   const intdh_ge *Y = (const intdh_ge *)YY;
308   octet *p;
309   mp *t;
310   int rc;
311
312   t = mpmont_reduce(&g->mm, MP_NEW, Y->X);
313   switch (fmt) {
314     case DHFMT_HASH: if (g->ser == DHSER_CONSTLEN) goto std;
315     case DHFMT_VAR:
316       rc = buf_putmp(b, t);
317       break;
318     case DHFMT_STD: std:
319       if ((p = buf_get(b, g->gesz)) == 0)
320         rc = -1;
321       else {
322         mp_storeb(t, p, g->gesz);
323         rc = 0;
324       }
325       break;
326     default:
327       abort();
328   }
329   MP_DROP(t);
330   return (rc);
331 }
332
333 static int intdh_checkge(const dhgrp *gg, const dhge *YY)
334 {
335   const intdh_grp *g = (const intdh_grp *)gg;
336   const intdh_ge *Y = (const intdh_ge *)YY;
337   mp *T;
338   int rc = 0;
339
340   if (MP_EQ(Y->X, g->mm.r)) rc = -1;
341   T = mpmont_expr(&g->mm, MP_NEW, Y->X, g->q);
342   if (!MP_EQ(T, g->mm.r)) rc = -1;
343   MP_DROP(T);
344   return (rc);
345 }
346
347 static int intdh_eq(const dhgrp *gg, const dhge *YY, const dhge *ZZ)
348 {
349   const intdh_ge *Y = (const intdh_ge *)YY, *Z = (const intdh_ge *)ZZ;
350   return (MP_EQ(Y->X, Z->X));
351 }
352
353 static dhge *intdh_mul(const dhgrp *gg, const dhsc *xx, const dhge *YY)
354 {
355   const intdh_grp *g = (const intdh_grp *)gg;
356   const intdh_sc *x = (const intdh_sc *)xx;
357   const intdh_ge *Y = (const intdh_ge *)YY;
358   intdh_ge *Z = CREATE(intdh_ge);
359
360   Z->X = mpmont_expr(&g->mm, MP_NEW, Y ? Y->X : g->G, x->x);
361   return ((dhge *)Z);
362 }
363
364 #ifndef NTRACE
365 static const char *intdh_gestr(const dhgrp *gg, const dhge *YY)
366 {
367   const intdh_grp *g = (const intdh_grp *)gg;
368   const intdh_ge *Y = (const intdh_ge *)YY;
369   mp *t = mpmont_reduce(&g->mm, MP_NEW, Y->X);
370   const char *p = mpstr(t, 10);
371   MP_DROP(t);
372   return (p);
373 }
374 #endif
375
376 static void intdh_freege(const dhgrp *gg, dhge *YY)
377   { intdh_ge *Y = (intdh_ge *)YY; MP_DROP(Y->X); DESTROY(Y); }
378
379 /*----- Elliptic curve groups ---------------------------------------------*/
380
381 typedef struct ecdh_grp {
382   dhgrp _g;
383   ec_info ei;
384   ec P;
385   int ser;
386 } ecdh_grp;
387
388 typedef struct ecdh_sc { mp *x; } ecdh_sc;
389 typedef struct ecdh_ge { ec Q; } ecdh_ge;
390
391 static dhgrp *ecdh_mkgroup(key_file *kf, key *k, const char *cstr, dstr *e)
392 {
393   ecdh_grp *g;
394   ec_info ei;
395   int ser;
396   const char *err;
397
398   if ((ser = get_serialization(kf, k, e)) < 0) return (0);
399   if ((err = ec_getinfo(&ei, cstr)) != 0) {
400     a_format(e, "decode-failed", "%s", err, A_END);
401     return (0);
402   }
403   g = CREATE(ecdh_grp);
404   g->ser = ser;
405   g->ei = ei;
406   EC_CREATE(&g->P); EC_IN(g->ei.c, &g->P, &g->ei.g);
407   g->_g.scsz = mp_octets(g->ei.r);
408   return (&g->_g);
409 }
410
411 static dhsc *ecdh_mptosc(const dhgrp *gg, mp *z)
412 {
413   const ecdh_grp *g = (const ecdh_grp *)gg;
414   ecdh_sc *x = CREATE(ecdh_sc);
415   x->x = MP_NEW; mp_div(0, &x->x, z, g->ei.r);
416   return ((dhsc *)x);
417 }
418
419 static dhge *ecdh_ectoge(const dhgrp *gg, ec *Q)
420 {
421   const ecdh_grp *g = (const ecdh_grp *)gg;
422   ecdh_ge *Y = CREATE(ecdh_ge); EC_CREATE(&Y->Q);
423   EC_IN(g->ei.c, &Y->Q, Q);
424   if (EC_CHECK(g->ei.c, &Y->Q))
425     { EC_DESTROY(&Y->Q); DESTROY(Y); return (0); }
426   return ((dhge *)Y);
427 }
428
429 KLOAD(ecdh, ec, EC,
430       { if ((kd->grp = ecdh_mkgroup(kf, k, p.cstr, e)) == 0) goto fail; },
431       { kd->k = ecdh_mptosc(kd->grp, p.x); },
432       { if ((kd->K = ecdh_ectoge(kd->grp, &p.p)) == 0) {
433           a_format(e, "bad-public-vector", A_END);
434           goto fail;
435         }
436       })
437
438 static const char *ecdh_checkgrp(const dhgrp *gg)
439 {
440   const ecdh_grp *g = (const ecdh_grp *)gg;
441   return (ec_checkinfo(&g->ei, &rand_global));
442 }
443
444 static void ecdh_grpinfo(const dhgrp *gg, admin *adm)
445 {
446   const ecdh_grp *g = (const ecdh_grp *)gg;
447   a_info(adm,
448          "kx-group=ec",
449          "kx-group-order-bits=%lu", (unsigned long)mp_bits(g->ei.r),
450          "kx-group-elt-bits=%lu", (unsigned long)2*g->ei.c->f->nbits,
451          A_END);
452 }
453
454 #ifndef NTRACE
455 static void addfestr(field *f, mp *x, mptext_stringctx *sc)
456   { addmpstr(x, F_TYPE(f) == FTY_PRIME ? 10 : 16, sc); }
457
458 static void addintfestr(field *f, mp *x, mptext_stringctx *sc)
459   { mp *t = F_OUT(f, MP_NEW, x); addfestr(f, x, sc); MP_DROP(t); }
460
461 static const char *intfestr(field *f, mp *x)
462 {
463   mptext_stringctx sc;
464   setupstr(&sc);
465   addintfestr(f, x, &sc);
466   return (donestr(&sc));
467 }
468
469 static void ecdh_tracegrp(const dhgrp *gg)
470 {
471   const ecdh_grp *g = (const ecdh_grp *)gg;
472   const ec_curve *c = g->ei.c;
473   field *f = c->f;
474
475   trace(T_CRYPTO, "crypto: group type `ec'");
476   switch (F_TYPE(f)) {
477     case FTY_PRIME:
478       trace(T_CRYPTO, "crypto: prime field `%s'", F_NAME(f));
479       trace(T_CRYPTO, "crypto: p = %s", mpstr(f->q, 10));
480       break;
481     case FTY_BINARY:
482       trace(T_CRYPTO, "crypto: binary field `%s'", F_NAME(f));
483       trace(T_CRYPTO, "crypto: degree = %lu", f->nbits - 1);
484       break;
485     default:
486       trace(T_CRYPTO, "crypto: unknown field type! `%s'", F_NAME(f));
487       break;
488   }
489   trace(T_CRYPTO, "crypto: curve type `%s'", EC_NAME(c));
490   trace(T_CRYPTO, "crypto: curve a = %s", intfestr(f, c->a));
491   trace(T_CRYPTO, "crypto: curve b = %s", intfestr(f, c->b));
492   trace(T_CRYPTO, "crypto: n = %s", mpstr(g->ei.r, 10));
493   trace(T_CRYPTO, "crypto: h = %s", mpstr(g->ei.h, 10));
494 }
495 #endif
496
497 static int ecdh_samegrpp(const dhgrp *gg, const dhgrp *hh)
498 {
499   const ecdh_grp *g = (const ecdh_grp *)gg, *h = (const ecdh_grp *)hh;
500   return (ec_sameinfop(&g->ei, &h->ei) &&
501           g->ser == h->ser);
502 }
503
504 static void ecdh_freegrp(dhgrp *gg)
505 {
506   ecdh_grp *g = (ecdh_grp *)gg;
507   EC_DESTROY(&g->P); ec_freeinfo(&g->ei);
508   DESTROY(g);
509 }
510
511 static dhsc *ecdh_ldsc(const dhgrp *gg, const void *p, size_t sz)
512 {
513   const ecdh_grp *g = (const ecdh_grp *)gg;
514   ecdh_sc *x = CREATE(ecdh_sc);
515   mp *t = mp_loadb(MP_NEW, p, sz);
516   mp_div(0, &t, t, g->ei.r); x->x = t;
517   return ((dhsc *)x);
518 }
519
520 static int ecdh_stsc(const dhgrp *gg, void *p, size_t sz, const dhsc *xx)
521 {
522   const ecdh_sc *x = (const ecdh_sc *)xx;
523   mp_storeb(x->x, p, sz);
524   return (0);
525 }
526
527 static dhsc *ecdh_randsc(const dhgrp *gg)
528 {
529   const ecdh_grp *g = (const ecdh_grp *)gg;
530   ecdh_sc *x = CREATE(ecdh_sc);
531   x->x = mprand_range(MP_NEW, g->ei.r, &rand_global, 0);
532   return ((dhsc *)x);
533 }
534
535 #ifndef NTRACE
536 static const char *ecdh_scstr(const dhgrp *gg, const dhsc *xx)
537 {
538   const ecdh_sc *x = (const ecdh_sc *)xx;
539   return (mpstr(x->x, 10));
540 }
541 #endif
542
543 static void ecdh_freesc(const dhgrp *gg, dhsc *xx)
544   { ecdh_sc *x = (ecdh_sc *)xx; MP_DROP(x->x); DESTROY(x); }
545
546 static dhge *ecdh_ldge(const dhgrp *gg, buf *b, int fmt)
547 {
548   const ecdh_grp *g = (const ecdh_grp *)gg;
549   ecdh_ge *Y;
550   ec T = EC_INIT;
551
552   switch (fmt) {
553     case DHFMT_HASH: if (g->ser == DHSER_CONSTLEN) goto std;
554     case DHFMT_VAR: if (buf_getec(b, &T)) return (0); break;
555     case DHFMT_STD: std: if (ec_getraw(g->ei.c, b, &T)) return (0); break;
556     default:
557       abort();
558   }
559   EC_IN(g->ei.c, &T, &T);
560   Y = CREATE(ecdh_ge); Y->Q = T;
561   return ((dhge *)Y);
562 }
563
564 static int ecdh_stge(const dhgrp *gg, buf *b, const dhge *YY, int fmt)
565 {
566   const ecdh_grp *g = (const ecdh_grp *)gg;
567   const ecdh_ge *Y = (const ecdh_ge *)YY;
568   ec T = EC_INIT;
569   int rc;
570
571   EC_OUT(g->ei.c, &T, &Y->Q);
572   switch (fmt) {
573     case DHFMT_HASH: if (g->ser == DHSER_CONSTLEN) goto std;
574     case DHFMT_VAR: rc = buf_putec(b, &T); break;
575     case DHFMT_STD: std: rc = ec_putraw(g->ei.c, b, &T); break;
576     default: abort();
577   }
578   EC_DESTROY(&T);
579   return (rc);
580 }
581
582 static int ecdh_checkge(const dhgrp *gg, const dhge *YY)
583 {
584   const ecdh_grp *g = (const ecdh_grp *)gg;
585   const ecdh_ge *Y = (const ecdh_ge *)YY;
586   ec T = EC_INIT;
587   int rc = 0;
588
589   if (EC_ATINF(&Y->Q)) rc = -1;
590   ec_imul(g->ei.c, &T, &Y->Q, g->ei.r);
591   if (!EC_ATINF(&T)) rc = -1;
592   EC_DESTROY(&T);
593   return (rc);
594 }
595
596 static int ecdh_eq(const dhgrp *gg, const dhge *YY, const dhge *ZZ)
597 {
598   const ecdh_grp *g = (const ecdh_grp *)gg;
599   const ecdh_ge *Y = (const ecdh_ge *)YY, *Z = (const ecdh_ge *)ZZ;
600   ec T = EC_INIT, U = EC_INIT; int rc;
601   EC_FIX(g->ei.c, &T, &Y->Q); EC_FIX(g->ei.c, &U, &Z->Q);
602   rc = EC_EQ(&T, &U);
603   EC_DESTROY(&T); EC_DESTROY(&U);
604   return (rc);
605 }
606
607 static dhge *ecdh_mul(const dhgrp *gg, const dhsc *xx, const dhge *YY)
608 {
609   const ecdh_grp *g = (const ecdh_grp *)gg;
610   const ecdh_sc *x = (const ecdh_sc *)xx;
611   const ecdh_ge *Y = (const ecdh_ge *)YY;
612   ecdh_ge *Z = CREATE(ecdh_ge); EC_CREATE(&Z->Q);
613
614   ec_imul(g->ei.c, &Z->Q, Y ? &Y->Q : &g->P, x->x);
615   return ((dhge *)Z);
616 }
617
618 #ifndef NTRACE
619 static const char *ecdh_gestr(const dhgrp *gg, const dhge *YY)
620 {
621   const ecdh_grp *g = (const ecdh_grp *)gg;
622   const ecdh_ge *Y = (const ecdh_ge *)YY;
623   ec T = EC_INIT;
624   field *f = g->ei.c->f;
625   mptext_stringctx sc;
626
627   if (EC_ATINF(&Y->Q)) return ("inf");
628   setupstr(&sc);
629   EC_OUT(g->ei.c, &T, &Y->Q);
630   addfestr(f, T.x, &sc);
631   addlitstr(", ", &sc);
632   addfestr(f, T.y, &sc);
633   EC_DESTROY(&T);
634   return (donestr(&sc));
635 }
636 #endif
637
638 static void ecdh_freege(const dhgrp *gg, dhge *YY)
639   { ecdh_ge *Y = (ecdh_ge *)YY; EC_DESTROY(&Y->Q); DESTROY(Y); }
640
641 /*----- The X25519 and similar groups -------------------------------------*/
642
643 #define XDHS(_)                                                         \
644   _(x25519, X25519, "curve25519", 252, 255)                             \
645   _(x448, X448, "ed448-goldilocks", 446, 448)
646
647 #ifdef NTRACE
648 #  define XDHTRACE(xdh, XDH, gname)
649 #else
650
651    static const char *binstr(const octet *p, size_t sz)
652    {
653      char *q;
654
655      for (q = (char *)buf_u; sz--; p++, q += 2) sprintf(q, "%02x", *p);
656      return ((const char *)buf_u);
657    }
658
659 #  define XDHTRACE(xdh, XDH, gname)                                     \
660      static void xdh##_tracegrp(const dhgrp *g)                         \
661        { trace(T_CRYPTO, "crypto: group type `" gname "'"); }           \
662                                                                         \
663      static const char *xdh##_scstr(const dhgrp *g, const dhsc *xx)     \
664      {                                                                  \
665        const xdh##_sc *x = (const xdh##_sc *)xx;                        \
666        return (binstr(x->x, XDH##_KEYSZ));                              \
667      }                                                                  \
668                                                                         \
669      static const char *xdh##_gestr(const dhgrp *g, const dhge *YY)     \
670      {                                                                  \
671        const xdh##_ge *Y = (const xdh##_ge *)YY;                        \
672        return (binstr(Y->X, XDH##_PUBSZ));                              \
673      }
674 #endif
675
676 #define XDHDEF(xdh, XDH, gname, groupbits, fieldbits)                   \
677                                                                         \
678   typedef struct xdh##_sc { octet x[XDH##_KEYSZ]; } xdh##_sc;           \
679   typedef struct xdh##_ge { octet X[XDH##_PUBSZ]; } xdh##_ge;           \
680                                                                         \
681   XDHTRACE(xdh, XDH, gname)                                             \
682                                                                         \
683   static dhsc *xdh##_bintosc(const key_bin *b)                          \
684   {                                                                     \
685     xdh##_sc *x;                                                        \
686                                                                         \
687     if (b->sz != XDH##_KEYSZ) return (0);                               \
688     x = CREATE(xdh##_sc);                                               \
689     memcpy(x->x, b->k, XDH##_KEYSZ);                                    \
690     return ((dhsc *)x);                                                 \
691   }                                                                     \
692                                                                         \
693   static dhge *xdh##_bintoge(const key_bin *b)                          \
694   {                                                                     \
695     xdh##_ge *Y;                                                        \
696                                                                         \
697     if (b->sz != XDH##_PUBSZ) return (0);                               \
698     Y = CREATE(xdh##_ge);                                               \
699     memcpy(Y->X, b->k, XDH##_PUBSZ);                                    \
700     return ((dhge *)Y);                                                 \
701   }                                                                     \
702                                                                         \
703   KLOAD(xdh, xdh, XDH,                                                  \
704         { kd->grp = CREATE(dhgrp);                                      \
705           kd->grp->scsz = XDH##_KEYSZ;                                  \
706         },                                                              \
707         { if ((kd->k = xdh##_bintosc(&p.priv)) == 0) {                  \
708             a_format(e, "bad-private-key", A_END);                      \
709             goto fail;                                                  \
710           }                                                             \
711         },                                                              \
712         { if ((kd->K = xdh##_bintoge(&p.pub)) == 0) {                   \
713             a_format(e, "bad-public-vector", A_END);                    \
714             goto fail;                                                  \
715           }                                                             \
716         })                                                              \
717                                                                         \
718   static const char *xdh##_checkgrp(const dhgrp *g)                     \
719     { return (0); }                                                     \
720                                                                         \
721   static void xdh##_grpinfo(const dhgrp *g, admin *adm)                 \
722   {                                                                     \
723     a_info(adm,                                                         \
724            "kx-group=" gname,                                           \
725            "kx-group-order-bits=%d", (groupbits),                       \
726            "kx-group-elt-bits=%d", (fieldbits),                         \
727            A_END);                                                      \
728   }                                                                     \
729                                                                         \
730   static int xdh##_samegrpp(const dhgrp *g, const dhgrp *hh)            \
731     { return (1); }                                                     \
732                                                                         \
733   static void xdh##_freegrp(dhgrp *g)                                   \
734     { DESTROY(g); }                                                     \
735                                                                         \
736   static dhsc *xdh##_ldsc(const dhgrp *g, const void *p, size_t sz)     \
737   {                                                                     \
738     xdh##_sc *x;                                                        \
739     if (sz != XDH##_KEYSZ) return (0);                                  \
740     x = CREATE(xdh##_sc);                                               \
741     memcpy(x->x, p, XDH##_KEYSZ);                                       \
742     return ((dhsc *)x);                                                 \
743   }                                                                     \
744                                                                         \
745   static int xdh##_stsc(const dhgrp *g, void *p, size_t sz,             \
746                         const dhsc *xx)                                 \
747   {                                                                     \
748     const xdh##_sc *x = (const xdh##_sc *)xx;                           \
749     if (sz != XDH##_KEYSZ) return (-1);                                 \
750     memcpy(p, x->x, XDH##_KEYSZ);                                       \
751     return (0);                                                         \
752   }                                                                     \
753                                                                         \
754   static dhsc *xdh##_randsc(const dhgrp *g)                             \
755   {                                                                     \
756     xdh##_sc *x = CREATE(xdh##_sc);                                     \
757     rand_get(RAND_GLOBAL, x->x, XDH##_KEYSZ);                           \
758     return ((dhsc *)x);                                                 \
759   }                                                                     \
760                                                                         \
761   static void xdh##_freesc(const dhgrp *g, dhsc *xx)                    \
762     { xdh##_sc *x = (xdh##_sc *)xx; DESTROY(x); }                       \
763                                                                         \
764   static dhge *xdh##_ldge(const dhgrp *g, buf *b, int fmt)              \
765   {                                                                     \
766     xdh##_ge *Y;                                                        \
767     const octet *p;                                                     \
768                                                                         \
769     if ((p = buf_get(b, XDH##_PUBSZ)) == 0) return (0);                 \
770     Y = CREATE(xdh##_ge); memcpy(Y->X, p, XDH##_PUBSZ);                 \
771     return ((dhge *)Y);                                                 \
772   }                                                                     \
773                                                                         \
774   static int xdh##_stge(const dhgrp *g, buf *b,                         \
775                         const dhge *YY, int fmt)                        \
776   {                                                                     \
777     const xdh##_ge *Y = (const xdh##_ge *)YY;                           \
778     return (buf_put(b, Y->X, XDH##_PUBSZ));                             \
779   }                                                                     \
780                                                                         \
781   static int xdh##_checkge(const dhgrp *g, const dhge *YY)              \
782     { return (0); }                                                     \
783                                                                         \
784   static int xdh##_eq(const dhgrp *g, const dhge *YY, const dhge *ZZ)   \
785   {                                                                     \
786     const xdh##_ge                                                      \
787       *Y = (const xdh##_ge *)YY, *Z = (const xdh##_ge *)ZZ;             \
788     return (ct_memeq(Y->X, Z->X, XDH##_PUBSZ));                         \
789   }                                                                     \
790                                                                         \
791   static dhge *xdh##_mul(const dhgrp *g,                                \
792                          const dhsc *xx, const dhge *YY)                \
793   {                                                                     \
794     const xdh##_sc *x = (const xdh##_sc *)xx;                           \
795     const xdh##_ge *Y = (const xdh##_ge *)YY;                           \
796     xdh##_ge *Z = CREATE(xdh##_ge);                                     \
797                                                                         \
798     xdh(Z->X, x->x, Y ? Y->X : xdh##_base);                             \
799     return ((dhge *)Z);                                                 \
800   }                                                                     \
801                                                                         \
802   static void xdh##_freege(const dhgrp *g, dhge *YY)                    \
803     { xdh##_ge *Y = (xdh##_ge *)YY; DESTROY(Y); }
804
805 XDHS(XDHDEF)
806
807 #undef XDHDEF
808
809 /*----- Diffie--Hellman group table ---------------------------------------*/
810
811 const dhops dhtab[] = {
812
813 #define COMMA ,
814
815 #define DH(name, pre)                                                   \
816   { name, pre##_ldpriv, pre##_ldpub, pre##_checkgrp,                    \
817     pre##_grpinfo, T( pre##_tracegrp COMMA ) pre##_samegrpp,            \
818     pre##_freegrp,                                                      \
819     pre##_ldsc, pre##_stsc, pre##_randsc, T( pre##_scstr COMMA )        \
820     pre##_freesc,                                                       \
821     pre##_ldge, pre##_stge, pre##_checkge, pre##_eq, pre##_mul,         \
822     T( pre##_gestr COMMA ) pre##_freege },                              \
823
824   DH("dh", intdh)
825   DH("ec", ecdh)
826
827 #define XDHDH(xdh, XDH, gname, groupbits, fieldbits) DH(#xdh, xdh)
828   XDHS(XDHDH)
829 #undef XDHDH
830
831 #undef DH
832
833   { 0 }
834 };
835
836 /*----- That's all, folks -------------------------------------------------*/