]> de.git.xonotic.org Git - xonotic/d0_blind_id.git/blob - d0_blind_id.c
TomsFastMath support, performs at 80% GMP performance...
[xonotic/d0_blind_id.git] / d0_blind_id.c
1 /*
2  * FILE:        d0_blind_id.c
3  * AUTHOR:      Rudolf Polzer - divVerent@xonotic.org
4  * 
5  * Copyright (c) 2010, Rudolf Polzer
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the copyright holder nor the names of contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  * 
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $Format:commit %H$
33  * $Id$
34  */
35
36 #include "d0_blind_id.h"
37
38 #include <stdio.h>
39 #include <string.h>
40 #include "d0_bignum.h"
41 #include "sha2.h"
42
43 // old "positive" protocol, uses one extra mod_inv in verify stages
44 // #define D0_BLIND_ID_POSITIVE_PROTOCOL
45
46 // our SHA is SHA-256
47 #define SHA_DIGESTSIZE 32
48 const unsigned char *sha(unsigned char *h, const unsigned char *in, size_t len)
49 {
50         d0_blind_id_util_sha256((char *) h, (const char *) in, len);
51         return h;
52 }
53
54 // for zero knowledge, we need multiple instances of schnorr ID scheme... should normally be sequential
55 // parallel schnorr ID is not provably zero knowledge :(
56 //   (evil verifier can know all questions in advance, so sequential is disadvantage for him)
57 // we'll just live with a 1:1048576 chance of cheating, and support reauthenticating
58
59 #define SCHNORR_BITS 20
60 // probability of cheat: 2^(-bits+1)
61
62 #define SCHNORR_HASHSIZE SHA_DIGESTSIZE
63 // cannot be >= SHA_DIGESTSIZE
64 // *8 must be >= SCHNORR_BITS
65 // no need to save bits here
66
67 #define MSGSIZE 640 // ought to be enough for anyone
68
69 struct d0_blind_id_s
70 {
71         // signing (Xonotic pub and priv key)
72         d0_bignum_t *rsa_n, *rsa_e, *rsa_d;
73
74         // public data (Schnorr ID)
75         d0_bignum_t *schnorr_G;
76
77         // private data (player ID private key)
78         d0_bignum_t *schnorr_s;
79
80         // public data (player ID public key, this is what the server gets to know)
81         d0_bignum_t *schnorr_g_to_s;
82         d0_bignum_t *schnorr_H_g_to_s_signature; // 0 when signature is invalid
83         // as hash function H, we get the SHA1 and reinterpret as bignum - yes, it always is < 160 bits
84
85         // temp data
86         d0_bignum_t *rsa_blind_signature_camouflage; // random number blind signature
87
88         d0_bignum_t *r; // random number for schnorr ID
89         d0_bignum_t *t; // for DH key exchange
90         d0_bignum_t *g_to_t; // for DH key exchange
91         d0_bignum_t *other_g_to_t; // for DH key exchange
92         d0_bignum_t *challenge; // challenge
93
94         char msghash[SCHNORR_HASHSIZE]; // init hash
95         char msg[MSGSIZE]; // message
96         size_t msglen; // message length
97 };
98
99 //#define CHECKDEBUG
100 #ifdef CHECKDEBUG
101 #define CHECK(x) do { if(!(x)) { fprintf(stderr, "CHECK FAILED (%s:%d): %s\n", __FILE__, __LINE__, #x); goto fail; } } while(0)
102 #define CHECK_ASSIGN(var, value) do { d0_bignum_t *val; val = value; if(!val) { fprintf(stderr, "CHECK FAILED (%s:%d): %s\n", __FILE__, __LINE__, #value); goto fail; } var = val; } while(0)
103 #else
104 #define CHECK(x) do { if(!(x)) goto fail; } while(0)
105 #define CHECK_ASSIGN(var, value) do { d0_bignum_t *val; val = value; if(!val) goto fail; var = val; } while(0)
106 #endif
107
108 #define USING(x) if(!(ctx->x)) return 0
109 #define REPLACING(x)
110
111 // safe to use
112 static d0_bignum_t *zero, *one, *four;
113
114 static d0_bignum_t *temp0, *temp1, *temp2, *temp3, *temp4;
115 static void *tempmutex = NULL; // hold this mutex when using temp0 to temp4
116 #define USINGTEMPS() int locked = 0
117 #define LOCKTEMPS() do { if(!locked) d0_lockmutex(tempmutex); locked = 1; } while(0)
118 #define UNLOCKTEMPS() do { if(locked) d0_unlockmutex(tempmutex); locked = 0; } while(0);
119
120 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_INITIALIZE(void)
121 {
122         USINGTEMPS();
123         d0_initfuncs();
124         tempmutex = d0_createmutex();
125         LOCKTEMPS();
126         CHECK(d0_bignum_INITIALIZE());
127         CHECK_ASSIGN(zero, d0_bignum_int(zero, 0));
128         CHECK_ASSIGN(one, d0_bignum_int(one, 1));
129         CHECK_ASSIGN(four, d0_bignum_int(four, 4));
130         CHECK_ASSIGN(temp0, d0_bignum_int(temp0, 0));
131         CHECK_ASSIGN(temp1, d0_bignum_int(temp1, 0));
132         CHECK_ASSIGN(temp2, d0_bignum_int(temp2, 0));
133         CHECK_ASSIGN(temp3, d0_bignum_int(temp3, 0));
134         CHECK_ASSIGN(temp4, d0_bignum_int(temp4, 0));
135         UNLOCKTEMPS();
136         return 1;
137 fail:
138         UNLOCKTEMPS();
139         return 0;
140 }
141
142 void d0_blind_id_SHUTDOWN(void)
143 {
144         USINGTEMPS();
145         LOCKTEMPS();
146         d0_bignum_free(zero);
147         d0_bignum_free(one);
148         d0_bignum_free(four);
149         d0_bignum_free(temp0);
150         d0_bignum_free(temp1);
151         d0_bignum_free(temp2);
152         d0_bignum_free(temp3);
153         d0_bignum_free(temp4);
154         d0_bignum_SHUTDOWN();
155         UNLOCKTEMPS();
156         d0_destroymutex(tempmutex);
157         tempmutex = NULL;
158 }
159
160 // (G-1)/2
161 static d0_bignum_t *d0_dl_get_order(d0_bignum_t *o, const d0_bignum_t *G)
162 {
163         CHECK_ASSIGN(o, d0_bignum_sub(o, G, one));
164         CHECK(d0_bignum_shl(o, o, -1)); // order o = (G-1)/2
165         return o;
166 fail:
167         return NULL;
168 }
169 // 2o+1
170 d0_bignum_t *d0_dl_get_from_order(d0_bignum_t *G, const d0_bignum_t *o)
171 {
172         CHECK_ASSIGN(G, d0_bignum_shl(G, o, 1));
173         CHECK(d0_bignum_add(G, G, one));
174         return G;
175 fail:
176         return NULL;
177 }
178
179 // temps must NOT be locked when calling this
180 static D0_BOOL d0_dl_generate_key(size_t size, d0_bignum_t *G)
181 {
182         USINGTEMPS(); // using: temp0
183         if(size < 16)
184                 size = 16;
185         for(;;)
186         {
187                 LOCKTEMPS();
188                 CHECK(d0_bignum_rand_bit_exact(temp0, size-1));
189                 if(d0_bignum_isprime(temp0, 0) == 0)
190                         continue;
191                 CHECK(d0_dl_get_from_order(G, temp0));
192                 if(d0_bignum_isprime(G, 10) == 0)
193                         continue;
194                 if(d0_bignum_isprime(temp0, 10) == 0) // finish the previous test
195                         continue;
196                 UNLOCKTEMPS();
197                 break;
198         }
199         return 1;
200 fail:
201         UNLOCKTEMPS();
202         return 0;
203 }
204
205 // temps must NOT be locked when calling this
206 static D0_BOOL d0_rsa_generate_key(size_t size, d0_blind_id_t *ctx)
207 {
208         USINGTEMPS(); // uses temp1 to temp4
209         int fail = 0;
210         int gcdfail = 0;
211         int pb = (size + 1)/2;
212         int qb = size - pb;
213         if(pb < 8)
214                 pb = 8;
215         if(qb < 8)
216                 qb = 8;
217
218         // we use ctx->rsa_d for the first result so that we can unlock temps later
219         for (;;)
220         {
221                 LOCKTEMPS();
222                 CHECK(d0_bignum_rand_bit_exact(ctx->rsa_d, pb));
223                 if(d0_bignum_isprime(ctx->rsa_d, 10) == 0)
224                 {
225                         UNLOCKTEMPS();
226                         continue;
227                 }
228                 CHECK(d0_bignum_sub(temp2, ctx->rsa_d, one));
229                 CHECK(d0_bignum_gcd(temp4, NULL, NULL, temp2, ctx->rsa_e));
230                 if(!d0_bignum_cmp(temp4, one))
231                         break;
232                 if(++gcdfail == 3)
233                         goto fail;
234                 ++gcdfail;
235         }
236         UNLOCKTEMPS();
237
238         gcdfail = 0;
239         for (;;)
240         {
241                 LOCKTEMPS();
242                 CHECK(d0_bignum_rand_bit_exact(temp1, qb));
243                 if(!d0_bignum_cmp(temp1, ctx->rsa_d))
244                 {
245                         UNLOCKTEMPS();
246                         if(++fail == 3)
247                                 goto fail;
248                         continue;
249                 }
250                 fail = 0;
251                 if(d0_bignum_isprime(temp1, 10) == 0)
252                 {
253                         UNLOCKTEMPS();
254                         continue;
255                 }
256                 CHECK(d0_bignum_sub(temp3, temp1, one));
257                 CHECK(d0_bignum_gcd(temp4, NULL, NULL, temp3, ctx->rsa_e));
258                 if(!d0_bignum_cmp(temp4, one))
259                 {
260                         // we do NOT unlock, as we still need temp1 and temp3
261                         break;
262                 }
263                 UNLOCKTEMPS();
264                 if(++gcdfail == 3)
265                         goto fail;
266                 ++gcdfail;
267         }
268
269         // ctx->rsa_n = ctx->rsa_d*temp1
270         CHECK(d0_bignum_mul(ctx->rsa_n, ctx->rsa_d, temp1));
271
272         // ctx->rsa_d = ctx->rsa_e^-1 mod (ctx->rsa_d-1)(temp1-1)
273         CHECK(d0_bignum_sub(temp2, ctx->rsa_d, one)); // we can't reuse the value from above because temps were unlocked
274         CHECK(d0_bignum_mul(temp0, temp2, temp3));
275         CHECK(d0_bignum_mod_inv(ctx->rsa_d, ctx->rsa_e, temp0));
276         UNLOCKTEMPS();
277         return 1;
278 fail:
279         UNLOCKTEMPS();
280         return 0;
281 }
282
283 // temps must NOT be locked when calling this
284 static D0_BOOL d0_rsa_generate_key_fastreject(size_t size, d0_fastreject_function reject, d0_blind_id_t *ctx, void *pass)
285 {
286         USINGTEMPS(); // uses temp1 to temp4
287         int fail = 0;
288         int gcdfail = 0;
289         int pb = (size + 1)/2;
290         int qb = size - pb;
291         if(pb < 8)
292                 pb = 8;
293         if(qb < 8)
294                 qb = 8;
295
296         // we use ctx->rsa_d for the first result so that we can unlock temps later
297         for (;;)
298         {
299                 LOCKTEMPS();
300                 CHECK(d0_bignum_rand_bit_exact(ctx->rsa_d, pb));
301                 if(d0_bignum_isprime(ctx->rsa_d, 10) == 0)
302                 {
303                         UNLOCKTEMPS();
304                         continue;
305                 }
306                 CHECK(d0_bignum_sub(temp2, ctx->rsa_d, one));
307                 CHECK(d0_bignum_gcd(temp4, NULL, NULL, temp2, ctx->rsa_e));
308                 if(!d0_bignum_cmp(temp4, one))
309                         break;
310                 if(++gcdfail == 3)
311                         return 0;
312                 ++gcdfail;
313         }
314         UNLOCKTEMPS();
315
316         gcdfail = 0;
317         for (;;)
318         {
319                 LOCKTEMPS();
320                 CHECK(d0_bignum_rand_bit_exact(temp1, qb));
321                 if(!d0_bignum_cmp(temp1, ctx->rsa_d))
322                 {
323                         UNLOCKTEMPS();
324                         if(++fail == 3)
325                                 return 0;
326                         continue;
327                 }
328                 fail = 0;
329
330                 // n = ctx->rsa_d*temp1
331                 CHECK(d0_bignum_mul(ctx->rsa_n, ctx->rsa_d, temp1));
332                 if(reject(ctx, pass))
333                 {
334                         UNLOCKTEMPS();
335                         continue;
336                 }
337
338                 if(d0_bignum_isprime(temp1, 10) == 0)
339                 {
340                         UNLOCKTEMPS();
341                         continue;
342                 }
343                 CHECK(d0_bignum_sub(temp3, temp1, one));
344                 CHECK(d0_bignum_gcd(temp4, NULL, NULL, temp3, ctx->rsa_e));
345                 if(!d0_bignum_cmp(temp4, one))
346                 {
347                         // we do NOT unlock, as we still need temp3
348                         break;
349                 }
350                 UNLOCKTEMPS();
351                 if(++gcdfail == 3)
352                         return 0;
353                 ++gcdfail;
354         }
355
356         // ctx->rsa_d = ctx->rsa_e^-1 mod (ctx->rsa_d-1)(temp1-1)
357         CHECK(d0_bignum_sub(temp2, ctx->rsa_d, one)); // we can't reuse the value from above because temps were unlocked
358         CHECK(d0_bignum_mul(ctx->rsa_d, temp2, temp3));
359         CHECK(d0_bignum_mod_inv(ctx->rsa_d, ctx->rsa_e, temp0));
360         UNLOCKTEMPS();
361         return 1;
362 fail:
363         UNLOCKTEMPS();
364         return 0;
365 }
366
367 D0_WARN_UNUSED_RESULT D0_BOOL d0_longhash_destructive(unsigned char *convbuf, size_t sz, unsigned char *outbuf, size_t outbuflen)
368 {
369         size_t n, i;
370         char shabuf[32];
371
372         n = outbuflen;
373         while(n > SHA_DIGESTSIZE)
374         {
375                 memcpy(outbuf, sha(shabuf, convbuf, sz), SHA_DIGESTSIZE);
376                 outbuf += SHA_DIGESTSIZE;
377                 n -= SHA_DIGESTSIZE;
378                 for(i = 0; i < sz; ++i)
379                         if(++convbuf[i])
380                                 break; // stop until no carry
381         }
382         memcpy(outbuf, sha(shabuf, convbuf, sz), n);
383         return 1;
384 }
385
386 D0_WARN_UNUSED_RESULT D0_BOOL d0_longhash_bignum(const d0_bignum_t *in, unsigned char *outbuf, size_t outbuflen)
387 {
388         unsigned char convbuf[1024];
389         size_t sz;
390
391         CHECK(d0_bignum_export_unsigned(in, convbuf, sizeof(convbuf)) >= 0);
392         sz = (d0_bignum_size(in) + 7) / 8;
393         CHECK(d0_longhash_destructive(convbuf, sz, outbuf, outbuflen));
394         return 1;
395
396 fail:
397         return 0;
398 }
399
400 void d0_blind_id_clear(d0_blind_id_t *ctx)
401 {
402         if(ctx->rsa_n) d0_bignum_free(ctx->rsa_n);
403         if(ctx->rsa_e) d0_bignum_free(ctx->rsa_e);
404         if(ctx->rsa_d) d0_bignum_free(ctx->rsa_d);
405         if(ctx->schnorr_G) d0_bignum_free(ctx->schnorr_G);
406         if(ctx->schnorr_s) d0_bignum_free(ctx->schnorr_s);
407         if(ctx->schnorr_g_to_s) d0_bignum_free(ctx->schnorr_g_to_s);
408         if(ctx->schnorr_H_g_to_s_signature) d0_bignum_free(ctx->schnorr_H_g_to_s_signature);
409         if(ctx->rsa_blind_signature_camouflage) d0_bignum_free(ctx->rsa_blind_signature_camouflage);
410         if(ctx->r) d0_bignum_free(ctx->r);
411         if(ctx->challenge) d0_bignum_free(ctx->challenge);
412         if(ctx->t) d0_bignum_free(ctx->t);
413         if(ctx->g_to_t) d0_bignum_free(ctx->g_to_t);
414         if(ctx->other_g_to_t) d0_bignum_free(ctx->other_g_to_t);
415         memset(ctx, 0, sizeof(*ctx));
416 }
417
418 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_copy(d0_blind_id_t *ctx, const d0_blind_id_t *src)
419 {
420         d0_blind_id_clear(ctx);
421         if(src->rsa_n) CHECK_ASSIGN(ctx->rsa_n, d0_bignum_mov(NULL, src->rsa_n));
422         if(src->rsa_e) CHECK_ASSIGN(ctx->rsa_e, d0_bignum_mov(NULL, src->rsa_e));
423         if(src->rsa_d) CHECK_ASSIGN(ctx->rsa_d, d0_bignum_mov(NULL, src->rsa_d));
424         if(src->schnorr_G) CHECK_ASSIGN(ctx->schnorr_G, d0_bignum_mov(NULL, src->schnorr_G));
425         if(src->schnorr_s) CHECK_ASSIGN(ctx->schnorr_s, d0_bignum_mov(NULL, src->schnorr_s));
426         if(src->schnorr_g_to_s) CHECK_ASSIGN(ctx->schnorr_g_to_s, d0_bignum_mov(NULL, src->schnorr_g_to_s));
427         if(src->schnorr_H_g_to_s_signature) CHECK_ASSIGN(ctx->schnorr_H_g_to_s_signature, d0_bignum_mov(NULL, src->schnorr_H_g_to_s_signature));
428         if(src->rsa_blind_signature_camouflage) CHECK_ASSIGN(ctx->rsa_blind_signature_camouflage, d0_bignum_mov(NULL, src->rsa_blind_signature_camouflage));
429         if(src->r) CHECK_ASSIGN(ctx->r, d0_bignum_mov(NULL, src->r));
430         if(src->challenge) CHECK_ASSIGN(ctx->challenge, d0_bignum_mov(NULL, src->challenge));
431         if(src->t) CHECK_ASSIGN(ctx->t, d0_bignum_mov(NULL, src->t));
432         if(src->g_to_t) CHECK_ASSIGN(ctx->g_to_t, d0_bignum_mov(NULL, src->g_to_t));
433         if(src->other_g_to_t) CHECK_ASSIGN(ctx->other_g_to_t, d0_bignum_mov(NULL, src->other_g_to_t));
434         memcpy(ctx->msg, src->msg, sizeof(ctx->msg));
435         ctx->msglen = src->msglen;
436         memcpy(ctx->msghash, src->msghash, sizeof(ctx->msghash));
437         return 1;
438 fail:
439         d0_blind_id_clear(ctx);
440         return 0;
441 }
442
443 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_generate_private_key_fastreject(d0_blind_id_t *ctx, int k, d0_fastreject_function reject, void *pass)
444 {
445         REPLACING(rsa_e); REPLACING(rsa_d); REPLACING(rsa_n);
446
447         CHECK_ASSIGN(ctx->rsa_e, d0_bignum_int(ctx->rsa_e, 65537));
448         CHECK_ASSIGN(ctx->rsa_d, d0_bignum_zero(ctx->rsa_d));
449         CHECK_ASSIGN(ctx->rsa_n, d0_bignum_zero(ctx->rsa_n));
450         if(reject)
451                 CHECK(d0_rsa_generate_key_fastreject(k+1, reject, ctx, pass)); // must fit G for sure
452         else
453                 CHECK(d0_rsa_generate_key(k+1, ctx)); // must fit G for sure
454         return 1;
455 fail:
456         return 0;
457 }
458
459 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_generate_private_key(d0_blind_id_t *ctx, int k)
460 {
461         return d0_blind_id_generate_private_key_fastreject(ctx, k, NULL, NULL);
462 }
463
464 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_read_private_key(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
465 {
466         d0_iobuf_t *in = NULL;
467
468         REPLACING(rsa_n); REPLACING(rsa_e); REPLACING(rsa_d);
469
470         in = d0_iobuf_open_read(inbuf, inbuflen);
471
472         CHECK_ASSIGN(ctx->rsa_n, d0_iobuf_read_bignum(in, ctx->rsa_n));
473         CHECK_ASSIGN(ctx->rsa_e, d0_iobuf_read_bignum(in, ctx->rsa_e));
474         CHECK_ASSIGN(ctx->rsa_d, d0_iobuf_read_bignum(in, ctx->rsa_d));
475         return d0_iobuf_close(in, NULL);
476
477 fail:
478         d0_iobuf_close(in, NULL);
479         return 0;
480 }
481
482 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_read_public_key(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
483 {
484         d0_iobuf_t *in = NULL;
485
486         REPLACING(rsa_n); REPLACING(rsa_e);
487
488         in = d0_iobuf_open_read(inbuf, inbuflen);
489         CHECK_ASSIGN(ctx->rsa_n, d0_iobuf_read_bignum(in, ctx->rsa_n));
490         CHECK_ASSIGN(ctx->rsa_e, d0_iobuf_read_bignum(in, ctx->rsa_e));
491         return d0_iobuf_close(in, NULL);
492
493 fail:
494         d0_iobuf_close(in, NULL);
495         return 0;
496 }
497
498 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_write_private_key(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
499 {
500         d0_iobuf_t *out = NULL;
501
502         USING(rsa_n); USING(rsa_e); USING(rsa_d);
503
504         out = d0_iobuf_open_write(outbuf, *outbuflen);
505         CHECK(d0_iobuf_write_bignum(out, ctx->rsa_n));
506         CHECK(d0_iobuf_write_bignum(out, ctx->rsa_e));
507         CHECK(d0_iobuf_write_bignum(out, ctx->rsa_d));
508         return d0_iobuf_close(out, outbuflen);
509
510 fail:
511         d0_iobuf_close(out, outbuflen);
512         return 0;
513 }
514
515 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_write_public_key(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
516 {
517         d0_iobuf_t *out = NULL;
518
519         USING(rsa_n); USING(rsa_e);
520
521         out = d0_iobuf_open_write(outbuf, *outbuflen);
522         CHECK(d0_iobuf_write_bignum(out, ctx->rsa_n));
523         CHECK(d0_iobuf_write_bignum(out, ctx->rsa_e));
524         return d0_iobuf_close(out, outbuflen);
525
526 fail:
527         if(!d0_iobuf_close(out, outbuflen))
528                 return 0;
529         return 0;
530 }
531
532 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_fingerprint64_public_key(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
533 {
534         d0_iobuf_t *out = NULL;
535         unsigned char convbuf[2048];
536         d0_iobuf_t *conv = NULL;
537         size_t sz, n;
538         char shabuf[32];
539
540         USING(rsa_n); USING(rsa_e);
541
542         out = d0_iobuf_open_write(outbuf, *outbuflen);
543         conv = d0_iobuf_open_write(convbuf, sizeof(convbuf));
544
545         CHECK(d0_iobuf_write_bignum(conv, ctx->rsa_n));
546         CHECK(d0_iobuf_write_bignum(conv, ctx->rsa_e));
547         CHECK(d0_iobuf_close(conv, &sz));
548         conv = NULL;
549
550         n = (*outbuflen / 4) * 3;
551         if(n > SHA_DIGESTSIZE)
552                 n = SHA_DIGESTSIZE;
553         CHECK(d0_iobuf_write_raw(out, sha(shabuf, convbuf, sz), n) == n);
554         CHECK(d0_iobuf_conv_base64_out(out));
555
556         return d0_iobuf_close(out, outbuflen);
557
558 fail:
559         if(conv)
560                 d0_iobuf_close(conv, &sz);
561         d0_iobuf_close(out, outbuflen);
562         return 0;
563 }
564
565 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_generate_private_id_modulus(d0_blind_id_t *ctx)
566 {
567         USING(rsa_n);
568         REPLACING(schnorr_G);
569
570         CHECK_ASSIGN(ctx->schnorr_G, d0_bignum_zero(ctx->schnorr_G));
571         CHECK(d0_dl_generate_key(d0_bignum_size(ctx->rsa_n)-1, ctx->schnorr_G));
572         return 1;
573 fail:
574         return 0;
575 }
576
577 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_read_private_id_modulus(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
578 {
579         d0_iobuf_t *in = NULL;
580
581         REPLACING(schnorr_G);
582
583         in = d0_iobuf_open_read(inbuf, inbuflen);
584         CHECK_ASSIGN(ctx->schnorr_G, d0_iobuf_read_bignum(in, ctx->schnorr_G));
585         return d0_iobuf_close(in, NULL);
586
587 fail:
588         d0_iobuf_close(in, NULL);
589         return 0;
590 }
591
592 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_write_private_id_modulus(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
593 {
594         d0_iobuf_t *out = NULL;
595
596         USING(schnorr_G);
597
598         out = d0_iobuf_open_write(outbuf, *outbuflen);
599         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_G));
600         return d0_iobuf_close(out, outbuflen);
601
602 fail:
603         d0_iobuf_close(out, outbuflen);
604         return 0;
605 }
606
607 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_generate_private_id_start(d0_blind_id_t *ctx)
608 {
609         USINGTEMPS(); // temps: temp0 = order
610         USING(schnorr_G);
611         REPLACING(schnorr_s); REPLACING(schnorr_g_to_s);
612
613         LOCKTEMPS();
614         CHECK(d0_dl_get_order(temp0, ctx->schnorr_G));
615         CHECK_ASSIGN(ctx->schnorr_s, d0_bignum_rand_range(ctx->schnorr_s, zero, temp0));
616         CHECK_ASSIGN(ctx->schnorr_g_to_s, d0_bignum_mod_pow(ctx->schnorr_g_to_s, four, ctx->schnorr_s, ctx->schnorr_G));
617         CHECK_ASSIGN(ctx->schnorr_H_g_to_s_signature, d0_bignum_zero(ctx->schnorr_H_g_to_s_signature));
618         UNLOCKTEMPS();
619         return 1;
620
621 fail:
622         UNLOCKTEMPS();
623         return 0;
624 }
625
626 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_generate_private_id_request(d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
627 {
628         d0_iobuf_t *out = NULL;
629         unsigned char hashbuf[2048];
630         size_t sz;
631
632         USINGTEMPS(); // temps: temp0 rsa_blind_signature_camouflage^challenge, temp1 (4^s)*rsa_blind_signature_camouflage^challenge
633         USING(rsa_n); USING(rsa_e); USING(schnorr_g_to_s);
634         REPLACING(rsa_blind_signature_camouflage);
635
636         out = d0_iobuf_open_write(outbuf, *outbuflen);
637
638         CHECK_ASSIGN(ctx->rsa_blind_signature_camouflage, d0_bignum_rand_bit_atmost(ctx->rsa_blind_signature_camouflage, d0_bignum_size(ctx->rsa_n)));
639         CHECK(d0_bignum_mod_pow(temp0, ctx->rsa_blind_signature_camouflage, ctx->rsa_e, ctx->rsa_n));
640
641         // we will actually sign HA(4^s) to prevent a malleability attack!
642         LOCKTEMPS();
643         sz = (d0_bignum_size(ctx->rsa_n) + 7) / 8; // this is too long, so we have to take the value % rsa_n when "decrypting"
644         if(sz > sizeof(hashbuf))
645                 sz = sizeof(hashbuf);
646         CHECK(d0_longhash_bignum(ctx->schnorr_g_to_s, hashbuf, sz));
647         CHECK(d0_bignum_import_unsigned(temp2, hashbuf, sz));
648
649         // hash complete
650         CHECK(d0_bignum_mod_mul(temp1, temp2, temp0, ctx->rsa_n));
651         CHECK(d0_iobuf_write_bignum(out, temp1));
652         UNLOCKTEMPS();
653         return d0_iobuf_close(out, outbuflen);
654
655 fail:
656         UNLOCKTEMPS();
657         d0_iobuf_close(out, outbuflen);
658         return 0;
659 }
660
661 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_answer_private_id_request(const d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen, char *outbuf, size_t *outbuflen)
662 {
663         d0_iobuf_t *in = NULL;
664         d0_iobuf_t *out = NULL;
665
666         USINGTEMPS(); // temps: temp0 input, temp1 temp0^d
667         USING(rsa_d); USING(rsa_n);
668
669         in = d0_iobuf_open_read(inbuf, inbuflen);
670         out = d0_iobuf_open_write(outbuf, *outbuflen);
671
672         LOCKTEMPS();
673         CHECK(d0_iobuf_read_bignum(in, temp0));
674         CHECK(d0_bignum_mod_pow(temp1, temp0, ctx->rsa_d, ctx->rsa_n));
675         CHECK(d0_iobuf_write_bignum(out, temp1));
676
677         UNLOCKTEMPS();
678         d0_iobuf_close(in, NULL);
679         return d0_iobuf_close(out, outbuflen);
680
681 fail:
682         UNLOCKTEMPS();
683         d0_iobuf_close(in, NULL);
684         d0_iobuf_close(out, outbuflen);
685         return 0;
686 }
687
688 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_finish_private_id_request(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
689 {
690         d0_iobuf_t *in = NULL;
691
692         USINGTEMPS(); // temps: temp0 input, temp1 rsa_blind_signature_camouflage^-1
693         USING(rsa_blind_signature_camouflage); USING(rsa_n);
694         REPLACING(schnorr_H_g_to_s_signature);
695
696         in = d0_iobuf_open_read(inbuf, inbuflen);
697
698         LOCKTEMPS();
699
700         CHECK(d0_iobuf_read_bignum(in, temp0));
701         CHECK(d0_bignum_mod_inv(temp1, ctx->rsa_blind_signature_camouflage, ctx->rsa_n));
702         CHECK_ASSIGN(ctx->schnorr_H_g_to_s_signature, d0_bignum_mod_mul(ctx->schnorr_H_g_to_s_signature, temp0, temp1, ctx->rsa_n));
703
704         UNLOCKTEMPS();
705         return d0_iobuf_close(in, NULL);
706
707 fail:
708         UNLOCKTEMPS();
709         d0_iobuf_close(in, NULL);
710         return 0;
711 }
712
713 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_read_private_id_request_camouflage(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
714 {
715         d0_iobuf_t *in = NULL;
716
717         REPLACING(rsa_blind_signature_camouflage);
718
719         in = d0_iobuf_open_read(inbuf, inbuflen);
720
721         CHECK_ASSIGN(ctx->rsa_blind_signature_camouflage, d0_iobuf_read_bignum(in, ctx->rsa_blind_signature_camouflage));
722
723         return d0_iobuf_close(in, NULL);
724
725 fail:
726         d0_iobuf_close(in, NULL);
727         return 0;
728 }
729
730 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_write_private_id_request_camouflage(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
731 {
732         d0_iobuf_t *out = NULL;
733
734         USING(rsa_blind_signature_camouflage);
735
736         out = d0_iobuf_open_write(outbuf, *outbuflen);
737
738         CHECK(d0_iobuf_write_bignum(out, ctx->rsa_blind_signature_camouflage));
739
740         return d0_iobuf_close(out, outbuflen);
741
742 fail:
743         d0_iobuf_close(out, outbuflen);
744         return 0;
745 }
746
747 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_read_private_id(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
748 {
749         d0_iobuf_t *in = NULL;
750
751         REPLACING(schnorr_s); REPLACING(schnorr_g_to_s); REPLACING(schnorr_H_g_to_s_signature);
752
753         in = d0_iobuf_open_read(inbuf, inbuflen);
754
755         CHECK_ASSIGN(ctx->schnorr_s, d0_iobuf_read_bignum(in, ctx->schnorr_s));
756         CHECK_ASSIGN(ctx->schnorr_g_to_s, d0_iobuf_read_bignum(in, ctx->schnorr_g_to_s));
757         CHECK_ASSIGN(ctx->schnorr_H_g_to_s_signature, d0_iobuf_read_bignum(in, ctx->schnorr_H_g_to_s_signature));
758
759         return d0_iobuf_close(in, NULL);
760
761 fail:
762         d0_iobuf_close(in, NULL);
763         return 0;
764 }
765
766 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_read_public_id(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
767 {
768         d0_iobuf_t *in = NULL;
769
770         REPLACING(schnorr_g_to_s); REPLACING(schnorr_H_g_to_s_signature);
771
772         in = d0_iobuf_open_read(inbuf, inbuflen);
773
774         CHECK_ASSIGN(ctx->schnorr_g_to_s, d0_iobuf_read_bignum(in, ctx->schnorr_g_to_s));
775         CHECK_ASSIGN(ctx->schnorr_H_g_to_s_signature, d0_iobuf_read_bignum(in, ctx->schnorr_H_g_to_s_signature));
776
777         return d0_iobuf_close(in, NULL);
778
779 fail:
780         d0_iobuf_close(in, NULL);
781         return 0;
782 }
783
784 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_write_private_id(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
785 {
786         d0_iobuf_t *out = NULL;
787
788         USING(schnorr_s); USING(schnorr_g_to_s); USING(schnorr_H_g_to_s_signature);
789
790         out = d0_iobuf_open_write(outbuf, *outbuflen);
791
792         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_s));
793         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_g_to_s));
794         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_H_g_to_s_signature));
795
796         return d0_iobuf_close(out, outbuflen);
797
798 fail:
799         d0_iobuf_close(out, outbuflen);
800         return 0;
801 }
802
803 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_write_public_id(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
804 {
805         d0_iobuf_t *out = NULL;
806
807         USING(schnorr_g_to_s); USING(schnorr_H_g_to_s_signature);
808
809         out = d0_iobuf_open_write(outbuf, *outbuflen);
810
811         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_g_to_s));
812         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_H_g_to_s_signature));
813
814         return d0_iobuf_close(out, outbuflen);
815
816 fail:
817         d0_iobuf_close(out, outbuflen);
818         return 0;
819 }
820
821 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_authenticate_with_private_id_start(d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL send_modulus, const char *msg, size_t msglen, char *outbuf, size_t *outbuflen)
822 // start =
823 //   first run: send 4^s, 4^s signature
824 //   1. get random r, send HASH(4^r)
825 {
826         d0_iobuf_t *out = NULL;
827         unsigned char convbuf[1024];
828         d0_iobuf_t *conv = NULL;
829         size_t sz = 0;
830         D0_BOOL failed = 0;
831         char shabuf[32];
832
833         USINGTEMPS(); // temps: temp0 order, temp0 4^r
834         if(is_first)
835         {
836                 USING(schnorr_g_to_s); USING(schnorr_H_g_to_s_signature);
837         }
838         USING(schnorr_G);
839         REPLACING(r); REPLACING(t); REPLACING(g_to_t);
840
841         out = d0_iobuf_open_write(outbuf, *outbuflen);
842
843         if(is_first)
844         {
845                 // send ID
846                 if(send_modulus)
847                         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_G));
848                 CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_g_to_s));
849                 CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_H_g_to_s_signature));
850         }
851
852         // start schnorr ID scheme
853         // generate random number r; x = g^r; send hash of x, remember r, forget x
854         LOCKTEMPS();
855         CHECK(d0_dl_get_order(temp0, ctx->schnorr_G));
856 #ifdef RNG_XKCD
857         CHECK_ASSIGN(ctx->r, d0_bignum_int(ctx->r, 4)); // decided by fair dice roll
858 #else
859         CHECK_ASSIGN(ctx->r, d0_bignum_rand_range(ctx->r, zero, temp0));
860 #endif
861
862         // initialize Signed Diffie Hellmann
863         // we already have the group order in temp1
864 #ifdef RNG_XKCD
865         CHECK_ASSIGN(ctx->t, d0_bignum_int(ctx->t, 4)); // decided by fair dice roll
866 #else
867         CHECK_ASSIGN(ctx->t, d0_bignum_rand_range(ctx->t, zero, temp0));
868 #endif
869         // can we SOMEHOW do this with just one mod_pow?
870
871         CHECK(d0_bignum_mod_pow(temp0, four, ctx->r, ctx->schnorr_G));
872         CHECK_ASSIGN(ctx->g_to_t, d0_bignum_mod_pow(ctx->g_to_t, four, ctx->t, ctx->schnorr_G));
873         CHECK(!failed);
874
875         // hash it, hash it, everybody hash it
876         conv = d0_iobuf_open_write(convbuf, sizeof(convbuf));
877         CHECK(d0_iobuf_write_bignum(conv, temp0));
878         CHECK(d0_iobuf_write_bignum(conv, ctx->g_to_t));
879         CHECK(d0_iobuf_write_packet(conv, msg, msglen));
880         CHECK(d0_iobuf_write_bignum(conv, temp0));
881         UNLOCKTEMPS();
882         CHECK(d0_iobuf_write_bignum(conv, ctx->g_to_t));
883         d0_iobuf_close(conv, &sz);
884         conv = NULL;
885         CHECK(d0_iobuf_write_raw(out, sha(shabuf, convbuf, sz), SCHNORR_HASHSIZE) == SCHNORR_HASHSIZE);
886         CHECK(d0_iobuf_write_packet(out, msg, msglen));
887
888         return d0_iobuf_close(out, outbuflen);
889
890 fail:
891         UNLOCKTEMPS();
892         d0_iobuf_close(out, outbuflen);
893         return 0;
894 }
895
896 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_authenticate_with_private_id_challenge(d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL recv_modulus, const char *inbuf, size_t inbuflen, char *outbuf, size_t *outbuflen, D0_BOOL *status)
897 //   first run: get 4^s, 4^s signature
898 //   1. check sig
899 //   2. save HASH(4^r)
900 //   3. send challenge challenge of SCHNORR_BITS
901 {
902         d0_iobuf_t *in = NULL;
903         d0_iobuf_t *out = NULL;
904         unsigned char hashbuf[2048];
905         size_t sz;
906
907         USINGTEMPS(); // temps: temp0 order, temp0 signature check
908         if(is_first)
909         {
910                 REPLACING(schnorr_g_to_s); REPLACING(schnorr_H_g_to_s_signature);
911                 if(recv_modulus)
912                         REPLACING(schnorr_G);
913                 else
914                         USING(schnorr_G);
915         }
916         else
917         {
918                 USING(schnorr_g_to_s); USING(schnorr_H_g_to_s_signature);
919                 USING(schnorr_G);
920         }
921         USING(rsa_e); USING(rsa_n);
922         REPLACING(challenge); REPLACING(msg); REPLACING(msglen); REPLACING(msghash); REPLACING(r); REPLACING(t);
923
924         in = d0_iobuf_open_read(inbuf, inbuflen);
925         out = d0_iobuf_open_write(outbuf, *outbuflen);
926
927         if(is_first)
928         {
929                 if(recv_modulus)
930                 {
931                         CHECK_ASSIGN(ctx->schnorr_G, d0_iobuf_read_bignum(in, ctx->schnorr_G));
932                         CHECK(d0_bignum_cmp(ctx->schnorr_G, zero) > 0);
933                         CHECK(d0_bignum_cmp(ctx->schnorr_G, ctx->rsa_n) < 0);
934                 }
935                 CHECK_ASSIGN(ctx->schnorr_g_to_s, d0_iobuf_read_bignum(in, ctx->schnorr_g_to_s));
936                 CHECK(d0_bignum_cmp(ctx->schnorr_g_to_s, zero) >= 0);
937                 CHECK(d0_bignum_cmp(ctx->schnorr_g_to_s, ctx->schnorr_G) < 0);
938                 CHECK_ASSIGN(ctx->schnorr_H_g_to_s_signature, d0_iobuf_read_bignum(in, ctx->schnorr_H_g_to_s_signature));
939                 CHECK(d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, zero) >= 0);
940                 CHECK(d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, ctx->rsa_n) < 0);
941
942                 if(d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, zero))
943                 {
944                         // check signature of key (t = k^d, so, t^challenge = k)
945                         LOCKTEMPS();
946                         CHECK(d0_bignum_mod_pow(temp0, ctx->schnorr_H_g_to_s_signature, ctx->rsa_e, ctx->rsa_n));
947
948                         // we will actually sign SHA(4^s) to prevent a malleability attack!
949                         sz = (d0_bignum_size(ctx->rsa_n) + 7) / 8; // this is too long, so we have to take the value % rsa_n when "decrypting"
950                         if(sz > sizeof(hashbuf))
951                                 sz = sizeof(hashbuf);
952                         CHECK(d0_longhash_bignum(ctx->schnorr_g_to_s, hashbuf, sz));
953                         CHECK(d0_bignum_import_unsigned(temp2, hashbuf, sz));
954
955                         // + 7 / 8 is too large, so let's mod it
956                         CHECK(d0_bignum_divmod(NULL, temp1, temp2, ctx->rsa_n));
957
958                         // hash complete
959                         CHECK(d0_bignum_cmp(temp0, temp1) == 0);
960                 }
961         }
962
963         CHECK(d0_iobuf_read_raw(in, ctx->msghash, SCHNORR_HASHSIZE));
964         ctx->msglen = MSGSIZE;
965         CHECK(d0_iobuf_read_packet(in, ctx->msg, &ctx->msglen));
966
967         // send challenge
968 #ifdef RNG_XKCD
969         CHECK_ASSIGN(ctx->challenge, d0_bignum_int(ctx->challenge, 4)); // decided by fair dice roll
970 #else
971         CHECK_ASSIGN(ctx->challenge, d0_bignum_rand_bit_atmost(ctx->challenge, SCHNORR_BITS));
972 #endif
973         CHECK(d0_iobuf_write_bignum(out, ctx->challenge));
974
975         // Diffie Hellmann send
976         LOCKTEMPS();
977         CHECK(d0_dl_get_order(temp0, ctx->schnorr_G));
978 #ifdef RNG_XKCD
979         CHECK_ASSIGN(ctx->t, d0_bignum_int(ctx->t, 4)); // decided by fair dice roll
980 #else
981         CHECK_ASSIGN(ctx->t, d0_bignum_rand_range(ctx->t, zero, temp0));
982 #endif
983         CHECK(d0_bignum_mod_pow(temp0, four, ctx->t, ctx->schnorr_G));
984         CHECK(d0_iobuf_write_bignum(out, temp0));
985         UNLOCKTEMPS();
986
987         if(status)
988                 *status = !!d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, zero);
989
990         d0_iobuf_close(in, NULL);
991         return d0_iobuf_close(out, outbuflen);
992
993 fail:
994         UNLOCKTEMPS();
995         d0_iobuf_close(in, NULL);
996         d0_iobuf_close(out, outbuflen);
997         return 0;
998 }
999
1000 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_authenticate_with_private_id_response(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen, char *outbuf, size_t *outbuflen)
1001 //   1. read challenge challenge of SCHNORR_BITS
1002 //   2. reply with r + s * challenge mod order
1003 {
1004         d0_iobuf_t *in = NULL;
1005         d0_iobuf_t *out = NULL;
1006
1007         USINGTEMPS(); // temps: 0 order, 1 prod, 2 y, 3 challenge
1008         REPLACING(other_g_to_t); REPLACING(t);
1009         USING(schnorr_G); USING(schnorr_s); USING(r); USING(g_to_t);
1010
1011         in = d0_iobuf_open_read(inbuf, inbuflen);
1012         out = d0_iobuf_open_write(outbuf, *outbuflen);
1013
1014         LOCKTEMPS();
1015         CHECK(d0_iobuf_read_bignum(in, temp3));
1016         CHECK(d0_bignum_cmp(temp3, zero) >= 0);
1017         CHECK(d0_bignum_size(temp3) <= SCHNORR_BITS);
1018
1019         // send response for schnorr ID scheme
1020         // i.challenge. r + ctx->schnorr_s * temp3
1021         CHECK(d0_dl_get_order(temp0, ctx->schnorr_G));
1022         CHECK(d0_bignum_mod_mul(temp1, ctx->schnorr_s, temp3, temp0));
1023 #ifdef D0_BLIND_ID_POSITIVE_PROTOCOL
1024         CHECK(d0_bignum_mod_add(temp2, ctx->r, temp1, temp0));
1025 #else
1026         CHECK(d0_bignum_mod_sub(temp2, ctx->r, temp1, temp0));
1027 #endif
1028         CHECK(d0_iobuf_write_bignum(out, temp2));
1029         UNLOCKTEMPS();
1030
1031         // Diffie Hellmann recv
1032         CHECK_ASSIGN(ctx->other_g_to_t, d0_iobuf_read_bignum(in, ctx->other_g_to_t));
1033         CHECK(d0_bignum_cmp(ctx->other_g_to_t, zero) > 0);
1034         CHECK(d0_bignum_cmp(ctx->other_g_to_t, ctx->schnorr_G) < 0);
1035         // Diffie Hellmann send
1036         CHECK(d0_iobuf_write_bignum(out, ctx->g_to_t));
1037
1038         d0_iobuf_close(in, NULL);
1039         return d0_iobuf_close(out, outbuflen);
1040
1041 fail:
1042         UNLOCKTEMPS();
1043         d0_iobuf_close(in, NULL);
1044         d0_iobuf_close(out, outbuflen);
1045         return 0;
1046 }
1047
1048 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_authenticate_with_private_id_verify(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen, char *msg, size_t *msglen, D0_BOOL *status)
1049 //   1. read y = r + s * challenge mod order
1050 //   2. verify: g^y (g^s)^-challenge = g^(r+s*challenge-s*challenge) = g^r
1051 //      (check using H(g^r) which we know)
1052 {
1053         d0_iobuf_t *in = NULL;
1054         unsigned char convbuf[1024];
1055         d0_iobuf_t *conv = NULL;
1056         size_t sz;
1057         char shabuf[32];
1058
1059         USINGTEMPS(); // temps: 0 y 1 order
1060         USING(challenge); USING(schnorr_G);
1061         REPLACING(other_g_to_t);
1062
1063         in = d0_iobuf_open_read(inbuf, inbuflen);
1064
1065         LOCKTEMPS();
1066
1067         CHECK(d0_dl_get_order(temp1, ctx->schnorr_G));
1068         CHECK(d0_iobuf_read_bignum(in, temp0));
1069         CHECK(d0_bignum_cmp(temp0, zero) >= 0);
1070         CHECK(d0_bignum_cmp(temp0, temp1) < 0);
1071
1072         // verify schnorr ID scheme
1073 #ifdef D0_BLIND_ID_POSITIVE_PROTOCOL
1074         // we need 4^r = 4^temp0 (g^s)^-challenge
1075         CHECK(d0_bignum_mod_inv(temp1, ctx->schnorr_g_to_s, ctx->schnorr_G));
1076         CHECK(d0_bignum_mod_pow(temp2, temp1, ctx->challenge, ctx->schnorr_G));
1077 #else
1078         // we need 4^r = 4^temp0 (g^s)^challenge
1079         CHECK(d0_bignum_mod_pow(temp2, ctx->schnorr_g_to_s, ctx->challenge, ctx->schnorr_G));
1080 #endif
1081         CHECK(d0_bignum_mod_pow(temp1, four, temp0, ctx->schnorr_G));
1082         CHECK_ASSIGN(temp3, d0_bignum_mod_mul(temp3, temp1, temp2, ctx->schnorr_G));
1083
1084         // Diffie Hellmann recv
1085         CHECK_ASSIGN(ctx->other_g_to_t, d0_iobuf_read_bignum(in, ctx->other_g_to_t));
1086         CHECK(d0_bignum_cmp(ctx->other_g_to_t, zero) > 0);
1087         CHECK(d0_bignum_cmp(ctx->other_g_to_t, ctx->schnorr_G) < 0);
1088
1089         // hash it, hash it, everybody hash it
1090         conv = d0_iobuf_open_write(convbuf, sizeof(convbuf));
1091         CHECK(d0_iobuf_write_bignum(conv, temp3));
1092         CHECK(d0_iobuf_write_bignum(conv, ctx->other_g_to_t));
1093         CHECK(d0_iobuf_write_packet(conv, ctx->msg, ctx->msglen));
1094         CHECK(d0_iobuf_write_bignum(conv, temp3));
1095         UNLOCKTEMPS();
1096         CHECK(d0_iobuf_write_bignum(conv, ctx->other_g_to_t));
1097         d0_iobuf_close(conv, &sz);
1098         conv = NULL;
1099         if(memcmp(sha(shabuf, convbuf, sz), ctx->msghash, SCHNORR_HASHSIZE))
1100         {
1101                 // FAIL (not owned by player)
1102                 goto fail;
1103         }
1104
1105         if(status)
1106                 *status = !!d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, zero);
1107
1108         if(ctx->msglen <= *msglen)
1109                 memcpy(msg, ctx->msg, ctx->msglen);
1110         else
1111                 memcpy(msg, ctx->msg, *msglen);
1112         *msglen = ctx->msglen;
1113
1114         d0_iobuf_close(in, NULL);
1115         return 1;
1116
1117 fail:
1118         UNLOCKTEMPS();
1119         d0_iobuf_close(in, NULL);
1120         return 0;
1121 }
1122
1123 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_authenticate_with_private_id_generate_missing_signature(d0_blind_id_t *ctx)
1124 {
1125         size_t sz;
1126         unsigned char hashbuf[2048];
1127
1128         USINGTEMPS(); // temps: 2 hash
1129         REPLACING(schnorr_H_g_to_s_signature);
1130         USING(schnorr_g_to_s); USING(rsa_d); USING(rsa_n);
1131
1132         LOCKTEMPS();
1133
1134         // we will actually sign SHA(4^s) to prevent a malleability attack!
1135         sz = (d0_bignum_size(ctx->rsa_n) + 7) / 8; // this is too long, so we have to take the value % rsa_n when "decrypting"
1136         if(sz > sizeof(hashbuf))
1137                 sz = sizeof(hashbuf);
1138         CHECK(d0_longhash_bignum(ctx->schnorr_g_to_s, hashbuf, sz));
1139         LOCKTEMPS();
1140         CHECK(d0_bignum_import_unsigned(temp2, hashbuf, sz));
1141
1142         // + 7 / 8 is too large, so let's mod it
1143         CHECK(d0_bignum_divmod(NULL, temp1, temp2, ctx->rsa_n));
1144         CHECK(d0_bignum_mod_pow(ctx->schnorr_H_g_to_s_signature, temp1, ctx->rsa_d, ctx->rsa_n));
1145
1146         UNLOCKTEMPS();
1147         return 1;
1148
1149 fail:
1150         UNLOCKTEMPS();
1151         return 0;
1152 }
1153
1154 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_sign_with_private_id_sign_internal(d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL send_modulus, D0_BOOL with_msg, const char *message, size_t msglen, char *outbuf, size_t *outbuflen)
1155 {
1156         d0_iobuf_t *out = NULL;
1157         unsigned char *convbuf = NULL;
1158         unsigned char hashbuf[2048];
1159         d0_iobuf_t *conv = NULL;
1160         size_t sz = 0;
1161
1162         USINGTEMPS(); // temps: 0 order 1 4^r 2 hash
1163         if(is_first)
1164         {
1165                 USING(schnorr_g_to_s); USING(schnorr_H_g_to_s_signature);
1166         }
1167         USING(schnorr_G);
1168         USING(schnorr_s);
1169         REPLACING(r);
1170
1171         out = d0_iobuf_open_write(outbuf, *outbuflen);
1172
1173         if(is_first)
1174         {
1175                 // send ID
1176                 if(send_modulus)
1177                         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_G));
1178                 CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_g_to_s));
1179                 CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_H_g_to_s_signature));
1180         }
1181
1182         // start schnorr SIGNATURE scheme
1183         // generate random number r; x = g^r; send hash of H(m||r), remember r, forget x
1184         LOCKTEMPS();
1185         CHECK(d0_dl_get_order(temp0, ctx->schnorr_G));
1186         CHECK_ASSIGN(ctx->r, d0_bignum_rand_range(ctx->r, zero, temp0));
1187         CHECK(d0_bignum_mod_pow(temp1, four, ctx->r, ctx->schnorr_G));
1188
1189         // hash it, hash it, everybody hash it
1190         conv = d0_iobuf_open_write_p((void **) &convbuf, 0);
1191         CHECK(d0_iobuf_write_packet(conv, message, msglen));
1192         CHECK(d0_iobuf_write_bignum(conv, temp1));
1193         d0_iobuf_close(conv, &sz);
1194         conv = NULL;
1195         CHECK(d0_longhash_destructive(convbuf, sz, hashbuf, (d0_bignum_size(temp0) + 7) / 8));
1196         d0_free(convbuf);
1197         convbuf = NULL;
1198         CHECK(d0_bignum_import_unsigned(temp2, hashbuf, (d0_bignum_size(temp0) + 7) / 8));
1199         CHECK(d0_iobuf_write_bignum(out, temp2));
1200
1201         // multiply with secret, sub k, modulo order
1202         CHECK(d0_bignum_mod_mul(temp1, temp2, ctx->schnorr_s, temp0));
1203 #ifdef D0_BLIND_ID_POSITIVE_PROTOCOL
1204         CHECK(d0_bignum_mod_add(temp2, ctx->r, temp1, temp0));
1205 #else
1206         CHECK(d0_bignum_mod_sub(temp2, ctx->r, temp1, temp0));
1207 #endif
1208         CHECK(d0_iobuf_write_bignum(out, temp2));
1209         UNLOCKTEMPS();
1210
1211         // write the message itself
1212         if(with_msg)
1213                 CHECK(d0_iobuf_write_packet(out, message, msglen));
1214
1215         return d0_iobuf_close(out, outbuflen);
1216
1217 fail:
1218         UNLOCKTEMPS();
1219         d0_iobuf_close(out, outbuflen);
1220         return 0;
1221 }
1222 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_sign_with_private_id_sign(d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL send_modulus, const char *message, size_t msglen, char *outbuf, size_t *outbuflen)
1223 {
1224         return d0_blind_id_sign_with_private_id_sign_internal(ctx, is_first, send_modulus, 1, message, msglen, outbuf, outbuflen);
1225 }
1226 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_sign_with_private_id_sign_detached(d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL send_modulus, const char *message, size_t msglen, char *outbuf, size_t *outbuflen)
1227 {
1228         return d0_blind_id_sign_with_private_id_sign_internal(ctx, is_first, send_modulus, 0, message, msglen, outbuf, outbuflen);
1229 }
1230
1231 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_sign_with_private_id_verify_internal(d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL recv_modulus, D0_BOOL with_msg, const char *inbuf, size_t inbuflen, char *msg, size_t *msglen, D0_BOOL *status)
1232 {
1233         d0_iobuf_t *in = NULL;
1234         d0_iobuf_t *conv = NULL;
1235         unsigned char *convbuf = NULL;
1236         unsigned char hashbuf[2048];
1237         size_t sz;
1238
1239         USINGTEMPS(); // temps: 0 sig^e 2 g^s 3 g^-s 4 order
1240         if(is_first)
1241         {
1242                 REPLACING(schnorr_g_to_s); REPLACING(schnorr_H_g_to_s_signature);
1243                 if(recv_modulus)
1244                         REPLACING(schnorr_G);
1245                 else
1246                         USING(schnorr_G);
1247         }
1248         else
1249         {
1250                 USING(schnorr_g_to_s); USING(schnorr_H_g_to_s_signature);
1251                 USING(schnorr_G);
1252         }
1253         USING(rsa_e); USING(rsa_n);
1254
1255         in = d0_iobuf_open_read(inbuf, inbuflen);
1256
1257         if(is_first)
1258         {
1259                 if(recv_modulus)
1260                 {
1261                         CHECK_ASSIGN(ctx->schnorr_G, d0_iobuf_read_bignum(in, ctx->schnorr_G));
1262                         CHECK(d0_bignum_cmp(ctx->schnorr_G, zero) > 0);
1263                         CHECK(d0_bignum_cmp(ctx->schnorr_G, ctx->rsa_n) < 0);
1264                 }
1265                 CHECK_ASSIGN(ctx->schnorr_g_to_s, d0_iobuf_read_bignum(in, ctx->schnorr_g_to_s));
1266                 CHECK(d0_bignum_cmp(ctx->schnorr_g_to_s, zero) >= 0);
1267                 CHECK(d0_bignum_cmp(ctx->schnorr_g_to_s, ctx->schnorr_G) < 0);
1268                 CHECK_ASSIGN(ctx->schnorr_H_g_to_s_signature, d0_iobuf_read_bignum(in, ctx->schnorr_H_g_to_s_signature));
1269                 CHECK(d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, zero) >= 0);
1270                 CHECK(d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, ctx->rsa_n) < 0);
1271
1272                 // check signature of key (t = k^d, so, t^challenge = k)
1273                 LOCKTEMPS();
1274                 CHECK(d0_bignum_mod_pow(temp0, ctx->schnorr_H_g_to_s_signature, ctx->rsa_e, ctx->rsa_n));
1275
1276                 // we will actually sign SHA(4^s) to prevent a malleability attack!
1277                 sz = (d0_bignum_size(ctx->rsa_n) + 7) / 8; // this is too long, so we have to take the value % rsa_n when "decrypting"
1278                 if(sz > sizeof(hashbuf))
1279                         sz = sizeof(hashbuf);
1280                 CHECK(d0_longhash_bignum(ctx->schnorr_g_to_s, hashbuf, sz));
1281                 CHECK(d0_bignum_import_unsigned(temp2, hashbuf, sz));
1282
1283                 // + 7 / 8 is too large, so let's mod it
1284                 CHECK(d0_bignum_divmod(NULL, temp1, temp2, ctx->rsa_n));
1285
1286                 // hash complete
1287                 if(d0_bignum_cmp(temp0, temp1))
1288                 {
1289                         // accept the key anyway, but mark as failed signature! will later return 0 in status
1290                         CHECK(d0_bignum_zero(ctx->schnorr_H_g_to_s_signature));
1291                 }
1292         }
1293
1294         CHECK(d0_dl_get_order(temp4, ctx->schnorr_G));
1295         CHECK(d0_iobuf_read_bignum(in, temp0)); // e == H(m || g^r)
1296         CHECK(d0_iobuf_read_bignum(in, temp1)); // x == (r - s*e) mod |G|
1297         if(with_msg)
1298                 CHECK(d0_iobuf_read_packet(in, msg, msglen));
1299
1300         // VERIFY: g^x * (g^s)^-e = g^(x - s*e) = g^r
1301
1302         // verify schnorr ID scheme
1303         // we need g^r = g^x (g^s)^e
1304         CHECK(d0_bignum_mod_pow(temp2, four, temp1, ctx->schnorr_G));
1305 #ifdef D0_BLIND_ID_POSITIVE_PROTOCOL
1306         CHECK(d0_bignum_mod_inv(temp3, ctx->schnorr_g_to_s, ctx->schnorr_G));
1307         CHECK(d0_bignum_mod_pow(temp1, temp3, temp0, ctx->schnorr_G));
1308 #else
1309         CHECK(d0_bignum_mod_pow(temp1, ctx->schnorr_g_to_s, temp0, ctx->schnorr_G));
1310 #endif
1311         CHECK_ASSIGN(temp3, d0_bignum_mod_mul(temp3, temp1, temp2, ctx->schnorr_G)); // temp3 now is g^r
1312
1313         // hash it, hash it, everybody hash it
1314         conv = d0_iobuf_open_write_p((void **) &convbuf, 0);
1315         CHECK(d0_iobuf_write_packet(conv, msg, *msglen));
1316         CHECK(d0_iobuf_write_bignum(conv, temp3));
1317         d0_iobuf_close(conv, &sz);
1318         conv = NULL;
1319         CHECK(d0_longhash_destructive(convbuf, sz, hashbuf, (d0_bignum_size(temp4) + 7) / 8));
1320         d0_free(convbuf);
1321         convbuf = NULL;
1322         CHECK(d0_bignum_import_unsigned(temp1, hashbuf, (d0_bignum_size(temp4) + 7) / 8));
1323
1324         // verify signature
1325         CHECK(!d0_bignum_cmp(temp0, temp1));
1326         UNLOCKTEMPS();
1327
1328         if(status)
1329                 *status = !!d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, zero);
1330
1331         d0_iobuf_close(in, NULL);
1332         return 1;
1333
1334 fail:
1335         UNLOCKTEMPS();
1336         d0_iobuf_close(in, NULL);
1337         return 0;
1338 }
1339 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_sign_with_private_id_verify(d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL recv_modulus, const char *inbuf, size_t inbuflen, char *msg, size_t *msglen, D0_BOOL *status)
1340 {
1341         return d0_blind_id_sign_with_private_id_verify_internal(ctx, is_first, recv_modulus, 1, inbuf, inbuflen, msg, msglen, status);
1342 }
1343 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_sign_with_private_id_verify_detached(d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL recv_modulus, const char *inbuf, size_t inbuflen, const char *msg, size_t msglen, D0_BOOL *status)
1344 {
1345         return d0_blind_id_sign_with_private_id_verify_internal(ctx, is_first, recv_modulus, 0, inbuf, inbuflen, (char *) msg, &msglen, status);
1346 }
1347
1348 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_fingerprint64_public_id(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
1349 {
1350         d0_iobuf_t *out = NULL;
1351         unsigned char convbuf[1024];
1352         d0_iobuf_t *conv = NULL;
1353         size_t sz, n;
1354         char shabuf[32];
1355
1356         USING(rsa_n);
1357         USING(rsa_e);
1358         USING(schnorr_g_to_s);
1359
1360         out = d0_iobuf_open_write(outbuf, *outbuflen);
1361         conv = d0_iobuf_open_write(convbuf, sizeof(convbuf));
1362
1363         CHECK(d0_iobuf_write_bignum(conv, ctx->rsa_n));
1364         CHECK(d0_iobuf_write_bignum(conv, ctx->rsa_e));
1365         CHECK(d0_iobuf_write_bignum(conv, ctx->schnorr_g_to_s));
1366         CHECK(d0_iobuf_close(conv, &sz));
1367         conv = NULL;
1368
1369         n = (*outbuflen / 4) * 3;
1370         if(n > SHA_DIGESTSIZE)
1371                 n = SHA_DIGESTSIZE;
1372         CHECK(d0_iobuf_write_raw(out, sha(shabuf, convbuf, sz), n) == n);
1373         CHECK(d0_iobuf_conv_base64_out(out));
1374
1375         return d0_iobuf_close(out, outbuflen);
1376
1377 fail:
1378         if(conv)
1379                 d0_iobuf_close(conv, &sz);
1380         d0_iobuf_close(out, outbuflen);
1381         return 0;
1382 }
1383
1384 D0_BOOL d0_blind_id_sessionkey_public_id(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
1385 {
1386         D0_BOOL ret;
1387
1388         USINGTEMPS(); // temps: temp0 result
1389         USING(t); USING(other_g_to_t); USING(schnorr_G);
1390
1391         LOCKTEMPS();
1392         CHECK(d0_bignum_mod_pow(temp0, ctx->other_g_to_t, ctx->t, ctx->schnorr_G));
1393         ret = d0_longhash_bignum(temp0, (unsigned char *) outbuf, *outbuflen);
1394         UNLOCKTEMPS();
1395         return ret;
1396
1397 fail:
1398         UNLOCKTEMPS();
1399         return 0;
1400 }
1401
1402 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_verify_public_id(const d0_blind_id_t *ctx, D0_BOOL *status)
1403 {
1404         unsigned char hashbuf[2048];
1405         size_t sz;
1406
1407         USINGTEMPS(); // temps: temp0 temp1 temp2
1408         USING(schnorr_H_g_to_s_signature); USING(rsa_e); USING(rsa_n); USING(schnorr_g_to_s);
1409
1410         if(d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, zero))
1411         {
1412                 // check signature of key (t = k^d, so, t^challenge = k)
1413                 LOCKTEMPS();
1414
1415                 CHECK(d0_bignum_mod_pow(temp0, ctx->schnorr_H_g_to_s_signature, ctx->rsa_e, ctx->rsa_n));
1416
1417                 // we will actually sign SHA(4^s) to prevent a malleability attack!
1418                 sz = (d0_bignum_size(ctx->rsa_n) + 7) / 8; // this is too long, so we have to take the value % rsa_n when "decrypting"
1419                 if(sz > sizeof(hashbuf))
1420                         sz = sizeof(hashbuf);
1421                 CHECK(d0_longhash_bignum(ctx->schnorr_g_to_s, hashbuf, sz));
1422                 CHECK(d0_bignum_import_unsigned(temp2, hashbuf, sz));
1423
1424                 // + 7 / 8 is too large, so let's mod it
1425                 CHECK(d0_bignum_divmod(NULL, temp1, temp2, ctx->rsa_n));
1426
1427                 // hash complete
1428                 CHECK(d0_bignum_cmp(temp0, temp1) == 0);
1429
1430                 *status = 1;
1431         }
1432         else
1433                 *status = 0;
1434
1435         UNLOCKTEMPS();
1436         return 1;
1437
1438 fail:
1439         UNLOCKTEMPS();
1440         return 0;
1441 }
1442
1443 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_verify_private_id(const d0_blind_id_t *ctx)
1444 {
1445         USINGTEMPS(); // temps: temp0 = g^s
1446         USING(schnorr_G); USING(schnorr_s); USING(schnorr_g_to_s);
1447
1448         LOCKTEMPS();
1449         CHECK(d0_bignum_mod_pow(temp0, four, ctx->schnorr_s, ctx->schnorr_G));
1450         CHECK(!d0_bignum_cmp(temp0, ctx->schnorr_g_to_s));
1451         UNLOCKTEMPS();
1452         return 1;
1453
1454 fail:
1455         UNLOCKTEMPS();
1456         return 0;
1457 }
1458
1459 d0_blind_id_t *d0_blind_id_new(void)
1460 {
1461         d0_blind_id_t *b = d0_malloc(sizeof(d0_blind_id_t));
1462         memset(b, 0, sizeof(*b));
1463         return b;
1464 }
1465
1466 void d0_blind_id_free(d0_blind_id_t *a)
1467 {
1468         d0_blind_id_clear(a);
1469         d0_free(a);
1470 }
1471
1472 void d0_blind_id_util_sha256(char *out, const char *in, size_t n)
1473 {
1474         SHA256_CTX context;
1475         SHA256_Init(&context);
1476         SHA256_Update(&context, (const unsigned char *) in, n);
1477         return SHA256_Final((unsigned char *) out, &context);
1478 }
1479
1480 void d0_blind_id_setmallocfuncs(d0_malloc_t *m, d0_free_t *f)
1481 {
1482         d0_setmallocfuncs(m, f);
1483 }
1484 void d0_blind_id_setmutexfuncs(d0_createmutex_t *c, d0_destroymutex_t *d, d0_lockmutex_t *l, d0_unlockmutex_t *u)
1485 {
1486         d0_setmutexfuncs(c, d, l, u);
1487 }