]> de.git.xonotic.org Git - xonotic/d0_blind_id.git/blob - d0_blind_id.c
fix one possible NULL bug in d0_bignum-gmp
[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         tempmutex = d0_createmutex();
124         LOCKTEMPS();
125         CHECK(d0_bignum_INITIALIZE());
126         CHECK_ASSIGN(zero, d0_bignum_int(zero, 0));
127         CHECK_ASSIGN(one, d0_bignum_int(one, 1));
128         CHECK_ASSIGN(four, d0_bignum_int(four, 4));
129         CHECK_ASSIGN(temp0, d0_bignum_int(temp0, 0));
130         CHECK_ASSIGN(temp1, d0_bignum_int(temp1, 0));
131         CHECK_ASSIGN(temp2, d0_bignum_int(temp2, 0));
132         CHECK_ASSIGN(temp3, d0_bignum_int(temp3, 0));
133         CHECK_ASSIGN(temp4, d0_bignum_int(temp4, 0));
134         UNLOCKTEMPS();
135         return 1;
136 fail:
137         UNLOCKTEMPS();
138         return 0;
139 }
140
141 void d0_blind_id_SHUTDOWN(void)
142 {
143         USINGTEMPS();
144         LOCKTEMPS();
145         d0_bignum_free(zero);
146         d0_bignum_free(one);
147         d0_bignum_free(four);
148         d0_bignum_free(temp0);
149         d0_bignum_free(temp1);
150         d0_bignum_free(temp2);
151         d0_bignum_free(temp3);
152         d0_bignum_free(temp4);
153         d0_bignum_SHUTDOWN();
154         UNLOCKTEMPS();
155         d0_destroymutex(tempmutex);
156         tempmutex = NULL;
157 }
158
159 // (G-1)/2
160 static d0_bignum_t *d0_dl_get_order(d0_bignum_t *o, const d0_bignum_t *G)
161 {
162         CHECK_ASSIGN(o, d0_bignum_sub(o, G, one));
163         CHECK(d0_bignum_shl(o, o, -1)); // order o = (G-1)/2
164         return o;
165 fail:
166         return NULL;
167 }
168 // 2o+1
169 d0_bignum_t *d0_dl_get_from_order(d0_bignum_t *G, const d0_bignum_t *o)
170 {
171         CHECK_ASSIGN(G, d0_bignum_shl(G, o, 1));
172         CHECK(d0_bignum_add(G, G, one));
173         return G;
174 fail:
175         return NULL;
176 }
177
178 // temps must NOT be locked when calling this
179 static D0_BOOL d0_dl_generate_key(size_t size, d0_bignum_t *G)
180 {
181         USINGTEMPS(); // using: temp0
182         if(size < 16)
183                 size = 16;
184         for(;;)
185         {
186                 LOCKTEMPS();
187                 CHECK(d0_bignum_rand_bit_exact(temp0, size-1));
188                 if(d0_bignum_isprime(temp0, 0) == 0)
189                         continue;
190                 CHECK(d0_dl_get_from_order(G, temp0));
191                 if(d0_bignum_isprime(G, 10) == 0)
192                         continue;
193                 if(d0_bignum_isprime(temp0, 10) == 0) // finish the previous test
194                         continue;
195                 UNLOCKTEMPS();
196                 break;
197         }
198         return 1;
199 fail:
200         UNLOCKTEMPS();
201         return 0;
202 }
203
204 // temps must NOT be locked when calling this
205 static D0_BOOL d0_rsa_generate_key(size_t size, d0_blind_id_t *ctx)
206 {
207         USINGTEMPS(); // uses temp1 to temp4
208         int fail = 0;
209         int gcdfail = 0;
210         int pb = (size + 1)/2;
211         int qb = size - pb;
212         if(pb < 8)
213                 pb = 8;
214         if(qb < 8)
215                 qb = 8;
216
217         // we use ctx->rsa_d for the first result so that we can unlock temps later
218         for (;;)
219         {
220                 LOCKTEMPS();
221                 CHECK(d0_bignum_rand_bit_exact(ctx->rsa_d, pb));
222                 if(d0_bignum_isprime(ctx->rsa_d, 10) == 0)
223                 {
224                         UNLOCKTEMPS();
225                         continue;
226                 }
227                 CHECK(d0_bignum_sub(temp2, ctx->rsa_d, one));
228                 CHECK(d0_bignum_gcd(temp4, NULL, NULL, temp2, ctx->rsa_e));
229                 if(!d0_bignum_cmp(temp4, one))
230                         break;
231                 if(++gcdfail == 3)
232                         goto fail;
233                 ++gcdfail;
234         }
235         UNLOCKTEMPS();
236
237         gcdfail = 0;
238         for (;;)
239         {
240                 LOCKTEMPS();
241                 CHECK(d0_bignum_rand_bit_exact(temp1, qb));
242                 if(!d0_bignum_cmp(temp1, ctx->rsa_d))
243                 {
244                         UNLOCKTEMPS();
245                         if(++fail == 3)
246                                 goto fail;
247                         continue;
248                 }
249                 fail = 0;
250                 if(d0_bignum_isprime(temp1, 10) == 0)
251                 {
252                         UNLOCKTEMPS();
253                         continue;
254                 }
255                 CHECK(d0_bignum_sub(temp3, temp1, one));
256                 CHECK(d0_bignum_gcd(temp4, NULL, NULL, temp3, ctx->rsa_e));
257                 if(!d0_bignum_cmp(temp4, one))
258                 {
259                         // we do NOT unlock, as we still need temp1 and temp3
260                         break;
261                 }
262                 UNLOCKTEMPS();
263                 if(++gcdfail == 3)
264                         goto fail;
265                 ++gcdfail;
266         }
267
268         // ctx->rsa_n = ctx->rsa_d*temp1
269         CHECK(d0_bignum_mul(ctx->rsa_n, ctx->rsa_d, temp1));
270
271         // ctx->rsa_d = ctx->rsa_e^-1 mod (ctx->rsa_d-1)(temp1-1)
272         CHECK(d0_bignum_sub(temp2, ctx->rsa_d, one)); // we can't reuse the value from above because temps were unlocked
273         CHECK(d0_bignum_mul(temp0, temp2, temp3));
274         CHECK(d0_bignum_mod_inv(ctx->rsa_d, ctx->rsa_e, temp0));
275         UNLOCKTEMPS();
276         return 1;
277 fail:
278         UNLOCKTEMPS();
279         return 0;
280 }
281
282 // temps must NOT be locked when calling this
283 static D0_BOOL d0_rsa_generate_key_fastreject(size_t size, d0_fastreject_function reject, d0_blind_id_t *ctx, void *pass)
284 {
285         USINGTEMPS(); // uses temp1 to temp4
286         int fail = 0;
287         int gcdfail = 0;
288         int pb = (size + 1)/2;
289         int qb = size - pb;
290         if(pb < 8)
291                 pb = 8;
292         if(qb < 8)
293                 qb = 8;
294
295         // we use ctx->rsa_d for the first result so that we can unlock temps later
296         for (;;)
297         {
298                 LOCKTEMPS();
299                 CHECK(d0_bignum_rand_bit_exact(ctx->rsa_d, pb));
300                 if(d0_bignum_isprime(ctx->rsa_d, 10) == 0)
301                 {
302                         UNLOCKTEMPS();
303                         continue;
304                 }
305                 CHECK(d0_bignum_sub(temp2, ctx->rsa_d, one));
306                 CHECK(d0_bignum_gcd(temp4, NULL, NULL, temp2, ctx->rsa_e));
307                 if(!d0_bignum_cmp(temp4, one))
308                         break;
309                 if(++gcdfail == 3)
310                         return 0;
311                 ++gcdfail;
312         }
313         UNLOCKTEMPS();
314
315         gcdfail = 0;
316         for (;;)
317         {
318                 LOCKTEMPS();
319                 CHECK(d0_bignum_rand_bit_exact(temp1, qb));
320                 if(!d0_bignum_cmp(temp1, ctx->rsa_d))
321                 {
322                         UNLOCKTEMPS();
323                         if(++fail == 3)
324                                 return 0;
325                         continue;
326                 }
327                 fail = 0;
328
329                 // n = ctx->rsa_d*temp1
330                 CHECK(d0_bignum_mul(ctx->rsa_n, ctx->rsa_d, temp1));
331                 if(reject(ctx, pass))
332                 {
333                         UNLOCKTEMPS();
334                         continue;
335                 }
336
337                 if(d0_bignum_isprime(temp1, 10) == 0)
338                 {
339                         UNLOCKTEMPS();
340                         continue;
341                 }
342                 CHECK(d0_bignum_sub(temp3, temp1, one));
343                 CHECK(d0_bignum_gcd(temp4, NULL, NULL, temp3, ctx->rsa_e));
344                 if(!d0_bignum_cmp(temp4, one))
345                 {
346                         // we do NOT unlock, as we still need temp3
347                         break;
348                 }
349                 UNLOCKTEMPS();
350                 if(++gcdfail == 3)
351                         return 0;
352                 ++gcdfail;
353         }
354
355         // ctx->rsa_d = ctx->rsa_e^-1 mod (ctx->rsa_d-1)(temp1-1)
356         CHECK(d0_bignum_sub(temp2, ctx->rsa_d, one)); // we can't reuse the value from above because temps were unlocked
357         CHECK(d0_bignum_mul(ctx->rsa_d, temp2, temp3));
358         CHECK(d0_bignum_mod_inv(ctx->rsa_d, ctx->rsa_e, temp0));
359         UNLOCKTEMPS();
360         return 1;
361 fail:
362         UNLOCKTEMPS();
363         return 0;
364 }
365
366 D0_WARN_UNUSED_RESULT D0_BOOL d0_longhash_destructive(unsigned char *convbuf, size_t sz, unsigned char *outbuf, size_t outbuflen)
367 {
368         size_t n, i;
369         char shabuf[32];
370
371         n = outbuflen;
372         while(n > SHA_DIGESTSIZE)
373         {
374                 memcpy(outbuf, sha(shabuf, convbuf, sz), SHA_DIGESTSIZE);
375                 outbuf += SHA_DIGESTSIZE;
376                 n -= SHA_DIGESTSIZE;
377                 for(i = 0; i < sz; ++i)
378                         if(++convbuf[i])
379                                 break; // stop until no carry
380         }
381         memcpy(outbuf, sha(shabuf, convbuf, sz), n);
382         return 1;
383 }
384
385 D0_WARN_UNUSED_RESULT D0_BOOL d0_longhash_bignum(const d0_bignum_t *in, unsigned char *outbuf, size_t outbuflen)
386 {
387         unsigned char convbuf[1024];
388         size_t sz;
389
390         CHECK(d0_bignum_export_unsigned(in, convbuf, sizeof(convbuf)) >= 0);
391         sz = (d0_bignum_size(in) + 7) / 8;
392         CHECK(d0_longhash_destructive(convbuf, sz, outbuf, outbuflen));
393         return 1;
394
395 fail:
396         return 0;
397 }
398
399 void d0_blind_id_clear(d0_blind_id_t *ctx)
400 {
401         if(ctx->rsa_n) d0_bignum_free(ctx->rsa_n);
402         if(ctx->rsa_e) d0_bignum_free(ctx->rsa_e);
403         if(ctx->rsa_d) d0_bignum_free(ctx->rsa_d);
404         if(ctx->schnorr_G) d0_bignum_free(ctx->schnorr_G);
405         if(ctx->schnorr_s) d0_bignum_free(ctx->schnorr_s);
406         if(ctx->schnorr_g_to_s) d0_bignum_free(ctx->schnorr_g_to_s);
407         if(ctx->schnorr_H_g_to_s_signature) d0_bignum_free(ctx->schnorr_H_g_to_s_signature);
408         if(ctx->rsa_blind_signature_camouflage) d0_bignum_free(ctx->rsa_blind_signature_camouflage);
409         if(ctx->r) d0_bignum_free(ctx->r);
410         if(ctx->challenge) d0_bignum_free(ctx->challenge);
411         if(ctx->t) d0_bignum_free(ctx->t);
412         if(ctx->g_to_t) d0_bignum_free(ctx->g_to_t);
413         if(ctx->other_g_to_t) d0_bignum_free(ctx->other_g_to_t);
414         memset(ctx, 0, sizeof(*ctx));
415 }
416
417 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_copy(d0_blind_id_t *ctx, const d0_blind_id_t *src)
418 {
419         d0_blind_id_clear(ctx);
420         if(src->rsa_n) CHECK_ASSIGN(ctx->rsa_n, d0_bignum_mov(NULL, src->rsa_n));
421         if(src->rsa_e) CHECK_ASSIGN(ctx->rsa_e, d0_bignum_mov(NULL, src->rsa_e));
422         if(src->rsa_d) CHECK_ASSIGN(ctx->rsa_d, d0_bignum_mov(NULL, src->rsa_d));
423         if(src->schnorr_G) CHECK_ASSIGN(ctx->schnorr_G, d0_bignum_mov(NULL, src->schnorr_G));
424         if(src->schnorr_s) CHECK_ASSIGN(ctx->schnorr_s, d0_bignum_mov(NULL, src->schnorr_s));
425         if(src->schnorr_g_to_s) CHECK_ASSIGN(ctx->schnorr_g_to_s, d0_bignum_mov(NULL, src->schnorr_g_to_s));
426         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));
427         if(src->rsa_blind_signature_camouflage) CHECK_ASSIGN(ctx->rsa_blind_signature_camouflage, d0_bignum_mov(NULL, src->rsa_blind_signature_camouflage));
428         if(src->r) CHECK_ASSIGN(ctx->r, d0_bignum_mov(NULL, src->r));
429         if(src->challenge) CHECK_ASSIGN(ctx->challenge, d0_bignum_mov(NULL, src->challenge));
430         if(src->t) CHECK_ASSIGN(ctx->t, d0_bignum_mov(NULL, src->t));
431         if(src->g_to_t) CHECK_ASSIGN(ctx->g_to_t, d0_bignum_mov(NULL, src->g_to_t));
432         if(src->other_g_to_t) CHECK_ASSIGN(ctx->other_g_to_t, d0_bignum_mov(NULL, src->other_g_to_t));
433         memcpy(ctx->msg, src->msg, sizeof(ctx->msg));
434         ctx->msglen = src->msglen;
435         memcpy(ctx->msghash, src->msghash, sizeof(ctx->msghash));
436         return 1;
437 fail:
438         d0_blind_id_clear(ctx);
439         return 0;
440 }
441
442 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)
443 {
444         REPLACING(rsa_e); REPLACING(rsa_d); REPLACING(rsa_n);
445
446         CHECK_ASSIGN(ctx->rsa_e, d0_bignum_int(ctx->rsa_e, 65537));
447         CHECK_ASSIGN(ctx->rsa_d, d0_bignum_zero(ctx->rsa_d));
448         CHECK_ASSIGN(ctx->rsa_n, d0_bignum_zero(ctx->rsa_n));
449         if(reject)
450                 CHECK(d0_rsa_generate_key_fastreject(k+1, reject, ctx, pass)); // must fit G for sure
451         else
452                 CHECK(d0_rsa_generate_key(k+1, ctx)); // must fit G for sure
453         return 1;
454 fail:
455         return 0;
456 }
457
458 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_generate_private_key(d0_blind_id_t *ctx, int k)
459 {
460         return d0_blind_id_generate_private_key_fastreject(ctx, k, NULL, NULL);
461 }
462
463 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_read_private_key(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
464 {
465         d0_iobuf_t *in = NULL;
466
467         REPLACING(rsa_n); REPLACING(rsa_e); REPLACING(rsa_d);
468
469         in = d0_iobuf_open_read(inbuf, inbuflen);
470
471         CHECK_ASSIGN(ctx->rsa_n, d0_iobuf_read_bignum(in, ctx->rsa_n));
472         CHECK_ASSIGN(ctx->rsa_e, d0_iobuf_read_bignum(in, ctx->rsa_e));
473         CHECK_ASSIGN(ctx->rsa_d, d0_iobuf_read_bignum(in, ctx->rsa_d));
474         return d0_iobuf_close(in, NULL);
475
476 fail:
477         d0_iobuf_close(in, NULL);
478         return 0;
479 }
480
481 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_read_public_key(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
482 {
483         d0_iobuf_t *in = NULL;
484
485         REPLACING(rsa_n); REPLACING(rsa_e);
486
487         in = d0_iobuf_open_read(inbuf, inbuflen);
488         CHECK_ASSIGN(ctx->rsa_n, d0_iobuf_read_bignum(in, ctx->rsa_n));
489         CHECK_ASSIGN(ctx->rsa_e, d0_iobuf_read_bignum(in, ctx->rsa_e));
490         return d0_iobuf_close(in, NULL);
491
492 fail:
493         d0_iobuf_close(in, NULL);
494         return 0;
495 }
496
497 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_write_private_key(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
498 {
499         d0_iobuf_t *out = NULL;
500
501         USING(rsa_n); USING(rsa_e); USING(rsa_d);
502
503         out = d0_iobuf_open_write(outbuf, *outbuflen);
504         CHECK(d0_iobuf_write_bignum(out, ctx->rsa_n));
505         CHECK(d0_iobuf_write_bignum(out, ctx->rsa_e));
506         CHECK(d0_iobuf_write_bignum(out, ctx->rsa_d));
507         return d0_iobuf_close(out, outbuflen);
508
509 fail:
510         d0_iobuf_close(out, outbuflen);
511         return 0;
512 }
513
514 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_write_public_key(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
515 {
516         d0_iobuf_t *out = NULL;
517
518         USING(rsa_n); USING(rsa_e);
519
520         out = d0_iobuf_open_write(outbuf, *outbuflen);
521         CHECK(d0_iobuf_write_bignum(out, ctx->rsa_n));
522         CHECK(d0_iobuf_write_bignum(out, ctx->rsa_e));
523         return d0_iobuf_close(out, outbuflen);
524
525 fail:
526         if(!d0_iobuf_close(out, outbuflen))
527                 return 0;
528         return 0;
529 }
530
531 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_fingerprint64_public_key(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
532 {
533         d0_iobuf_t *out = NULL;
534         unsigned char convbuf[2048];
535         d0_iobuf_t *conv = NULL;
536         size_t sz, n;
537         char shabuf[32];
538
539         USING(rsa_n); USING(rsa_e);
540
541         out = d0_iobuf_open_write(outbuf, *outbuflen);
542         conv = d0_iobuf_open_write(convbuf, sizeof(convbuf));
543
544         CHECK(d0_iobuf_write_bignum(conv, ctx->rsa_n));
545         CHECK(d0_iobuf_write_bignum(conv, ctx->rsa_e));
546         CHECK(d0_iobuf_close(conv, &sz));
547         conv = NULL;
548
549         n = (*outbuflen / 4) * 3;
550         if(n > SHA_DIGESTSIZE)
551                 n = SHA_DIGESTSIZE;
552         CHECK(d0_iobuf_write_raw(out, sha(shabuf, convbuf, sz), n) == n);
553         CHECK(d0_iobuf_conv_base64_out(out));
554
555         return d0_iobuf_close(out, outbuflen);
556
557 fail:
558         if(conv)
559                 d0_iobuf_close(conv, &sz);
560         d0_iobuf_close(out, outbuflen);
561         return 0;
562 }
563
564 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_generate_private_id_modulus(d0_blind_id_t *ctx)
565 {
566         USING(rsa_n);
567         REPLACING(schnorr_G);
568
569         CHECK_ASSIGN(ctx->schnorr_G, d0_bignum_zero(ctx->schnorr_G));
570         CHECK(d0_dl_generate_key(d0_bignum_size(ctx->rsa_n)-1, ctx->schnorr_G));
571         return 1;
572 fail:
573         return 0;
574 }
575
576 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_read_private_id_modulus(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
577 {
578         d0_iobuf_t *in = NULL;
579
580         REPLACING(schnorr_G);
581
582         in = d0_iobuf_open_read(inbuf, inbuflen);
583         CHECK_ASSIGN(ctx->schnorr_G, d0_iobuf_read_bignum(in, ctx->schnorr_G));
584         return d0_iobuf_close(in, NULL);
585
586 fail:
587         d0_iobuf_close(in, NULL);
588         return 0;
589 }
590
591 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_write_private_id_modulus(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
592 {
593         d0_iobuf_t *out = NULL;
594
595         USING(schnorr_G);
596
597         out = d0_iobuf_open_write(outbuf, *outbuflen);
598         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_G));
599         return d0_iobuf_close(out, outbuflen);
600
601 fail:
602         d0_iobuf_close(out, outbuflen);
603         return 0;
604 }
605
606 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_generate_private_id_start(d0_blind_id_t *ctx)
607 {
608         USINGTEMPS(); // temps: temp0 = order
609         USING(schnorr_G);
610         REPLACING(schnorr_s); REPLACING(schnorr_g_to_s);
611
612         LOCKTEMPS();
613         CHECK(d0_dl_get_order(temp0, ctx->schnorr_G));
614         CHECK_ASSIGN(ctx->schnorr_s, d0_bignum_rand_range(ctx->schnorr_s, zero, temp0));
615         CHECK_ASSIGN(ctx->schnorr_g_to_s, d0_bignum_mod_pow(ctx->schnorr_g_to_s, four, ctx->schnorr_s, ctx->schnorr_G));
616         CHECK_ASSIGN(ctx->schnorr_H_g_to_s_signature, d0_bignum_zero(ctx->schnorr_H_g_to_s_signature));
617         UNLOCKTEMPS();
618         return 1;
619
620 fail:
621         UNLOCKTEMPS();
622         return 0;
623 }
624
625 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_generate_private_id_request(d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
626 {
627         d0_iobuf_t *out = NULL;
628         unsigned char hashbuf[2048];
629         size_t sz;
630
631         USINGTEMPS(); // temps: temp0 rsa_blind_signature_camouflage^challenge, temp1 (4^s)*rsa_blind_signature_camouflage^challenge
632         USING(rsa_n); USING(rsa_e); USING(schnorr_g_to_s);
633         REPLACING(rsa_blind_signature_camouflage);
634
635         out = d0_iobuf_open_write(outbuf, *outbuflen);
636
637         CHECK_ASSIGN(ctx->rsa_blind_signature_camouflage, d0_bignum_rand_bit_atmost(ctx->rsa_blind_signature_camouflage, d0_bignum_size(ctx->rsa_n)));
638         CHECK(d0_bignum_mod_pow(temp0, ctx->rsa_blind_signature_camouflage, ctx->rsa_e, ctx->rsa_n));
639
640         // we will actually sign HA(4^s) to prevent a malleability attack!
641         LOCKTEMPS();
642         CHECK(d0_bignum_mov(temp2, ctx->schnorr_g_to_s));
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(temp2, 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                 // check signature of key (t = k^d, so, t^challenge = k)
943                 LOCKTEMPS();
944                 CHECK(d0_bignum_mod_pow(temp0, ctx->schnorr_H_g_to_s_signature, ctx->rsa_e, ctx->rsa_n));
945
946                 // we will actually sign SHA(4^s) to prevent a malleability attack!
947                 CHECK(d0_bignum_mov(temp2, ctx->schnorr_g_to_s));
948                 sz = (d0_bignum_size(ctx->rsa_n) + 7) / 8; // this is too long, so we have to take the value % rsa_n when "decrypting"
949                 if(sz > sizeof(hashbuf))
950                         sz = sizeof(hashbuf);
951                 CHECK(d0_longhash_bignum(temp2, hashbuf, sz));
952                 CHECK(d0_bignum_import_unsigned(temp2, hashbuf, sz));
953
954                 // + 7 / 8 is too large, so let's mod it
955                 CHECK(d0_bignum_divmod(NULL, temp1, temp2, ctx->rsa_n));
956
957                 // hash complete
958                 if(d0_bignum_cmp(temp0, temp1))
959                 {
960                         // accept the key anyway, but mark as failed signature! will later return 0 in status
961                         CHECK(d0_bignum_zero(ctx->schnorr_H_g_to_s_signature));
962                 }
963         }
964
965         CHECK(d0_iobuf_read_raw(in, ctx->msghash, SCHNORR_HASHSIZE));
966         ctx->msglen = MSGSIZE;
967         CHECK(d0_iobuf_read_packet(in, ctx->msg, &ctx->msglen));
968
969         // send challenge
970 #ifdef RNG_XKCD
971         CHECK_ASSIGN(ctx->challenge, d0_bignum_int(ctx->challenge, 4)); // decided by fair dice roll
972 #else
973         CHECK_ASSIGN(ctx->challenge, d0_bignum_rand_bit_atmost(ctx->challenge, SCHNORR_BITS));
974 #endif
975         CHECK(d0_iobuf_write_bignum(out, ctx->challenge));
976
977         // Diffie Hellmann send
978         LOCKTEMPS();
979         CHECK(d0_dl_get_order(temp0, ctx->schnorr_G));
980 #ifdef RNG_XKCD
981         CHECK_ASSIGN(ctx->t, d0_bignum_int(ctx->t, 4)); // decided by fair dice roll
982 #else
983         CHECK_ASSIGN(ctx->t, d0_bignum_rand_range(ctx->t, zero, temp0));
984 #endif
985         CHECK(d0_bignum_mod_pow(temp0, four, ctx->t, ctx->schnorr_G));
986         CHECK(d0_iobuf_write_bignum(out, temp0));
987         UNLOCKTEMPS();
988
989         if(status)
990                 *status = !!d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, zero);
991
992         d0_iobuf_close(in, NULL);
993         return d0_iobuf_close(out, outbuflen);
994
995 fail:
996         UNLOCKTEMPS();
997         d0_iobuf_close(in, NULL);
998         d0_iobuf_close(out, outbuflen);
999         return 0;
1000 }
1001
1002 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)
1003 //   1. read challenge challenge of SCHNORR_BITS
1004 //   2. reply with r + s * challenge mod order
1005 {
1006         d0_iobuf_t *in = NULL;
1007         d0_iobuf_t *out = NULL;
1008
1009         USINGTEMPS(); // temps: 0 order, 1 prod, 2 y, 3 challenge
1010         REPLACING(other_g_to_t); REPLACING(t);
1011         USING(schnorr_G); USING(schnorr_s); USING(r); USING(g_to_t);
1012
1013         in = d0_iobuf_open_read(inbuf, inbuflen);
1014         out = d0_iobuf_open_write(outbuf, *outbuflen);
1015
1016         LOCKTEMPS();
1017         CHECK(d0_iobuf_read_bignum(in, temp3));
1018         CHECK(d0_bignum_cmp(temp3, zero) >= 0);
1019         CHECK(d0_bignum_size(temp3) <= SCHNORR_BITS);
1020
1021         // send response for schnorr ID scheme
1022         // i.challenge. r + ctx->schnorr_s * temp3
1023         CHECK(d0_dl_get_order(temp0, ctx->schnorr_G));
1024         CHECK(d0_bignum_mod_mul(temp1, ctx->schnorr_s, temp3, temp0));
1025 #ifdef D0_BLIND_ID_POSITIVE_PROTOCOL
1026         CHECK(d0_bignum_mod_add(temp2, ctx->r, temp1, temp0));
1027 #else
1028         CHECK(d0_bignum_mod_sub(temp2, ctx->r, temp1, temp0));
1029 #endif
1030         CHECK(d0_iobuf_write_bignum(out, temp2));
1031         UNLOCKTEMPS();
1032
1033         // Diffie Hellmann recv
1034         CHECK_ASSIGN(ctx->other_g_to_t, d0_iobuf_read_bignum(in, ctx->other_g_to_t));
1035         CHECK(d0_bignum_cmp(ctx->other_g_to_t, zero) > 0);
1036         CHECK(d0_bignum_cmp(ctx->other_g_to_t, ctx->schnorr_G) < 0);
1037         // Diffie Hellmann send
1038         CHECK(d0_iobuf_write_bignum(out, ctx->g_to_t));
1039
1040         d0_iobuf_close(in, NULL);
1041         return d0_iobuf_close(out, outbuflen);
1042
1043 fail:
1044         UNLOCKTEMPS();
1045         d0_iobuf_close(in, NULL);
1046         d0_iobuf_close(out, outbuflen);
1047         return 0;
1048 }
1049
1050 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)
1051 //   1. read y = r + s * challenge mod order
1052 //   2. verify: g^y (g^s)^-challenge = g^(r+s*challenge-s*challenge) = g^r
1053 //      (check using H(g^r) which we know)
1054 {
1055         d0_iobuf_t *in = NULL;
1056         unsigned char convbuf[1024];
1057         d0_iobuf_t *conv = NULL;
1058         size_t sz;
1059         char shabuf[32];
1060
1061         USINGTEMPS(); // temps: 0 y 1 order
1062         USING(challenge); USING(schnorr_G);
1063         REPLACING(other_g_to_t);
1064
1065         in = d0_iobuf_open_read(inbuf, inbuflen);
1066
1067         LOCKTEMPS();
1068
1069         CHECK(d0_dl_get_order(temp1, ctx->schnorr_G));
1070         CHECK(d0_iobuf_read_bignum(in, temp0));
1071         CHECK(d0_bignum_cmp(temp0, zero) >= 0);
1072         CHECK(d0_bignum_cmp(temp0, temp1) < 0);
1073
1074         // verify schnorr ID scheme
1075 #ifdef D0_BLIND_ID_POSITIVE_PROTOCOL
1076         // we need 4^r = 4^temp0 (g^s)^-challenge
1077         CHECK(d0_bignum_mod_inv(temp1, ctx->schnorr_g_to_s, ctx->schnorr_G));
1078         CHECK(d0_bignum_mod_pow(temp2, temp1, ctx->challenge, ctx->schnorr_G));
1079 #else
1080         // we need 4^r = 4^temp0 (g^s)^challenge
1081         CHECK(d0_bignum_mod_pow(temp2, ctx->schnorr_g_to_s, ctx->challenge, ctx->schnorr_G));
1082 #endif
1083         CHECK(d0_bignum_mod_pow(temp1, four, temp0, ctx->schnorr_G));
1084         CHECK_ASSIGN(temp3, d0_bignum_mod_mul(temp3, temp1, temp2, ctx->schnorr_G));
1085
1086         // Diffie Hellmann recv
1087         CHECK_ASSIGN(ctx->other_g_to_t, d0_iobuf_read_bignum(in, ctx->other_g_to_t));
1088         CHECK(d0_bignum_cmp(ctx->other_g_to_t, zero) > 0);
1089         CHECK(d0_bignum_cmp(ctx->other_g_to_t, ctx->schnorr_G) < 0);
1090
1091         // hash it, hash it, everybody hash it
1092         conv = d0_iobuf_open_write(convbuf, sizeof(convbuf));
1093         CHECK(d0_iobuf_write_bignum(conv, temp3));
1094         CHECK(d0_iobuf_write_bignum(conv, ctx->other_g_to_t));
1095         CHECK(d0_iobuf_write_packet(conv, ctx->msg, ctx->msglen));
1096         CHECK(d0_iobuf_write_bignum(conv, temp3));
1097         UNLOCKTEMPS();
1098         CHECK(d0_iobuf_write_bignum(conv, ctx->other_g_to_t));
1099         d0_iobuf_close(conv, &sz);
1100         conv = NULL;
1101         if(memcmp(sha(shabuf, convbuf, sz), ctx->msghash, SCHNORR_HASHSIZE))
1102         {
1103                 // FAIL (not owned by player)
1104                 goto fail;
1105         }
1106
1107         if(status)
1108                 *status = !!d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, zero);
1109
1110         if(ctx->msglen <= *msglen)
1111                 memcpy(msg, ctx->msg, ctx->msglen);
1112         else
1113                 memcpy(msg, ctx->msg, *msglen);
1114         *msglen = ctx->msglen;
1115
1116         d0_iobuf_close(in, NULL);
1117         return 1;
1118
1119 fail:
1120         UNLOCKTEMPS();
1121         d0_iobuf_close(in, NULL);
1122         return 0;
1123 }
1124
1125 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_authenticate_with_private_id_generate_missing_signature(d0_blind_id_t *ctx)
1126 {
1127         size_t sz;
1128         unsigned char hashbuf[2048];
1129
1130         USINGTEMPS(); // temps: 2 hash
1131         REPLACING(schnorr_H_g_to_s_signature);
1132         USING(schnorr_g_to_s); USING(rsa_d); USING(rsa_n);
1133
1134         LOCKTEMPS();
1135
1136         // we will actually sign SHA(4^s) to prevent a malleability attack!
1137         sz = (d0_bignum_size(ctx->rsa_n) + 7) / 8; // this is too long, so we have to take the value % rsa_n when "decrypting"
1138         if(sz > sizeof(hashbuf))
1139                 sz = sizeof(hashbuf);
1140         CHECK(d0_longhash_bignum(ctx->schnorr_g_to_s, hashbuf, sz));
1141         LOCKTEMPS();
1142         CHECK(d0_bignum_import_unsigned(temp2, hashbuf, sz));
1143
1144         // + 7 / 8 is too large, so let's mod it
1145         CHECK(d0_bignum_divmod(NULL, temp1, temp2, ctx->rsa_n));
1146         CHECK(d0_bignum_mod_pow(ctx->schnorr_H_g_to_s_signature, temp1, ctx->rsa_d, ctx->rsa_n));
1147
1148         UNLOCKTEMPS();
1149         return 1;
1150
1151 fail:
1152         UNLOCKTEMPS();
1153         return 0;
1154 }
1155
1156 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)
1157 {
1158         d0_iobuf_t *out = NULL;
1159         unsigned char *convbuf = NULL;
1160         unsigned char hashbuf[2048];
1161         d0_iobuf_t *conv = NULL;
1162         size_t sz = 0;
1163
1164         USINGTEMPS(); // temps: 0 order 1 4^r 2 hash
1165         if(is_first)
1166         {
1167                 USING(schnorr_g_to_s); USING(schnorr_H_g_to_s_signature);
1168         }
1169         USING(schnorr_G);
1170         USING(schnorr_s);
1171         REPLACING(r);
1172
1173         out = d0_iobuf_open_write(outbuf, *outbuflen);
1174
1175         if(is_first)
1176         {
1177                 // send ID
1178                 if(send_modulus)
1179                         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_G));
1180                 CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_g_to_s));
1181                 CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_H_g_to_s_signature));
1182         }
1183
1184         // start schnorr SIGNATURE scheme
1185         // generate random number r; x = g^r; send hash of H(m||r), remember r, forget x
1186         LOCKTEMPS();
1187         CHECK(d0_dl_get_order(temp0, ctx->schnorr_G));
1188         CHECK_ASSIGN(ctx->r, d0_bignum_rand_range(ctx->r, zero, temp0));
1189         CHECK(d0_bignum_mod_pow(temp1, four, ctx->r, ctx->schnorr_G));
1190
1191         // hash it, hash it, everybody hash it
1192         conv = d0_iobuf_open_write_p((void **) &convbuf, 0);
1193         CHECK(d0_iobuf_write_packet(conv, message, msglen));
1194         CHECK(d0_iobuf_write_bignum(conv, temp1));
1195         d0_iobuf_close(conv, &sz);
1196         conv = NULL;
1197         CHECK(d0_longhash_destructive(convbuf, sz, hashbuf, (d0_bignum_size(temp0) + 7) / 8));
1198         d0_free(convbuf);
1199         convbuf = NULL;
1200         CHECK(d0_bignum_import_unsigned(temp2, hashbuf, (d0_bignum_size(temp0) + 7) / 8));
1201         CHECK(d0_iobuf_write_bignum(out, temp2));
1202
1203         // multiply with secret, sub k, modulo order
1204         CHECK(d0_bignum_mod_mul(temp1, temp2, ctx->schnorr_s, temp0));
1205 #ifdef D0_BLIND_ID_POSITIVE_PROTOCOL
1206         CHECK(d0_bignum_mod_add(temp2, ctx->r, temp1, temp0));
1207 #else
1208         CHECK(d0_bignum_mod_sub(temp2, ctx->r, temp1, temp0));
1209 #endif
1210         CHECK(d0_iobuf_write_bignum(out, temp2));
1211         UNLOCKTEMPS();
1212
1213         // write the message itself
1214         if(with_msg)
1215                 CHECK(d0_iobuf_write_packet(out, message, msglen));
1216
1217         return d0_iobuf_close(out, outbuflen);
1218
1219 fail:
1220         UNLOCKTEMPS();
1221         d0_iobuf_close(out, outbuflen);
1222         return 0;
1223 }
1224 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)
1225 {
1226         return d0_blind_id_sign_with_private_id_sign_internal(ctx, is_first, send_modulus, 1, message, msglen, outbuf, outbuflen);
1227 }
1228 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)
1229 {
1230         return d0_blind_id_sign_with_private_id_sign_internal(ctx, is_first, send_modulus, 0, message, msglen, outbuf, outbuflen);
1231 }
1232
1233 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)
1234 {
1235         d0_iobuf_t *in = NULL;
1236         d0_iobuf_t *conv = NULL;
1237         unsigned char *convbuf = NULL;
1238         unsigned char hashbuf[2048];
1239         size_t sz;
1240
1241         USINGTEMPS(); // temps: 0 sig^e 2 g^s 3 g^-s 4 order
1242         if(is_first)
1243         {
1244                 REPLACING(schnorr_g_to_s); REPLACING(schnorr_H_g_to_s_signature);
1245                 if(recv_modulus)
1246                         REPLACING(schnorr_G);
1247                 else
1248                         USING(schnorr_G);
1249         }
1250         else
1251         {
1252                 USING(schnorr_g_to_s); USING(schnorr_H_g_to_s_signature);
1253                 USING(schnorr_G);
1254         }
1255         USING(rsa_e); USING(rsa_n);
1256
1257         in = d0_iobuf_open_read(inbuf, inbuflen);
1258
1259         if(is_first)
1260         {
1261                 if(recv_modulus)
1262                 {
1263                         CHECK_ASSIGN(ctx->schnorr_G, d0_iobuf_read_bignum(in, ctx->schnorr_G));
1264                         CHECK(d0_bignum_cmp(ctx->schnorr_G, zero) > 0);
1265                         CHECK(d0_bignum_cmp(ctx->schnorr_G, ctx->rsa_n) < 0);
1266                 }
1267                 CHECK_ASSIGN(ctx->schnorr_g_to_s, d0_iobuf_read_bignum(in, ctx->schnorr_g_to_s));
1268                 CHECK(d0_bignum_cmp(ctx->schnorr_g_to_s, zero) >= 0);
1269                 CHECK(d0_bignum_cmp(ctx->schnorr_g_to_s, ctx->schnorr_G) < 0);
1270                 CHECK_ASSIGN(ctx->schnorr_H_g_to_s_signature, d0_iobuf_read_bignum(in, ctx->schnorr_H_g_to_s_signature));
1271                 CHECK(d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, zero) >= 0);
1272                 CHECK(d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, ctx->rsa_n) < 0);
1273
1274                 // check signature of key (t = k^d, so, t^challenge = k)
1275                 LOCKTEMPS();
1276                 CHECK(d0_bignum_mod_pow(temp0, ctx->schnorr_H_g_to_s_signature, ctx->rsa_e, ctx->rsa_n));
1277
1278                 // we will actually sign SHA(4^s) to prevent a malleability attack!
1279                 sz = (d0_bignum_size(ctx->rsa_n) + 7) / 8; // this is too long, so we have to take the value % rsa_n when "decrypting"
1280                 if(sz > sizeof(hashbuf))
1281                         sz = sizeof(hashbuf);
1282                 CHECK(d0_longhash_bignum(ctx->schnorr_g_to_s, hashbuf, sz));
1283                 CHECK(d0_bignum_import_unsigned(temp2, hashbuf, sz));
1284
1285                 // + 7 / 8 is too large, so let's mod it
1286                 CHECK(d0_bignum_divmod(NULL, temp1, temp2, ctx->rsa_n));
1287
1288                 // hash complete
1289                 if(d0_bignum_cmp(temp0, temp1))
1290                 {
1291                         // accept the key anyway, but mark as failed signature! will later return 0 in status
1292                         CHECK(d0_bignum_zero(ctx->schnorr_H_g_to_s_signature));
1293                 }
1294         }
1295
1296         CHECK(d0_dl_get_order(temp4, ctx->schnorr_G));
1297         CHECK(d0_iobuf_read_bignum(in, temp0)); // e == H(m || g^r)
1298         CHECK(d0_iobuf_read_bignum(in, temp1)); // x == (r - s*e) mod |G|
1299         if(with_msg)
1300                 CHECK(d0_iobuf_read_packet(in, msg, msglen));
1301
1302         // VERIFY: g^x * (g^s)^-e = g^(x - s*e) = g^r
1303
1304         // verify schnorr ID scheme
1305         // we need g^r = g^x (g^s)^e
1306         CHECK(d0_bignum_mod_pow(temp2, four, temp1, ctx->schnorr_G));
1307 #ifdef D0_BLIND_ID_POSITIVE_PROTOCOL
1308         CHECK(d0_bignum_mod_inv(temp3, ctx->schnorr_g_to_s, ctx->schnorr_G));
1309         CHECK(d0_bignum_mod_pow(temp1, temp3, temp0, ctx->schnorr_G));
1310 #else
1311         CHECK(d0_bignum_mod_pow(temp1, ctx->schnorr_g_to_s, temp0, ctx->schnorr_G));
1312 #endif
1313         CHECK_ASSIGN(temp3, d0_bignum_mod_mul(temp3, temp1, temp2, ctx->schnorr_G)); // temp3 now is g^r
1314
1315         // hash it, hash it, everybody hash it
1316         conv = d0_iobuf_open_write_p((void **) &convbuf, 0);
1317         CHECK(d0_iobuf_write_packet(conv, msg, *msglen));
1318         CHECK(d0_iobuf_write_bignum(conv, temp3));
1319         d0_iobuf_close(conv, &sz);
1320         conv = NULL;
1321         CHECK(d0_longhash_destructive(convbuf, sz, hashbuf, (d0_bignum_size(temp4) + 7) / 8));
1322         d0_free(convbuf);
1323         convbuf = NULL;
1324         CHECK(d0_bignum_import_unsigned(temp1, hashbuf, (d0_bignum_size(temp4) + 7) / 8));
1325
1326         // verify signature
1327         CHECK(!d0_bignum_cmp(temp0, temp1));
1328         UNLOCKTEMPS();
1329
1330         if(status)
1331                 *status = !!d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, zero);
1332
1333         d0_iobuf_close(in, NULL);
1334         return 1;
1335
1336 fail:
1337         UNLOCKTEMPS();
1338         d0_iobuf_close(in, NULL);
1339         return 0;
1340 }
1341 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)
1342 {
1343         return d0_blind_id_sign_with_private_id_verify_internal(ctx, is_first, recv_modulus, 1, inbuf, inbuflen, msg, msglen, status);
1344 }
1345 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)
1346 {
1347         return d0_blind_id_sign_with_private_id_verify_internal(ctx, is_first, recv_modulus, 0, inbuf, inbuflen, (char *) msg, &msglen, status);
1348 }
1349
1350 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_fingerprint64_public_id(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
1351 {
1352         d0_iobuf_t *out = NULL;
1353         unsigned char convbuf[1024];
1354         d0_iobuf_t *conv = NULL;
1355         size_t sz, n;
1356         char shabuf[32];
1357
1358         USING(rsa_n);
1359         USING(rsa_e);
1360         USING(schnorr_g_to_s);
1361
1362         out = d0_iobuf_open_write(outbuf, *outbuflen);
1363         conv = d0_iobuf_open_write(convbuf, sizeof(convbuf));
1364
1365         CHECK(d0_iobuf_write_bignum(conv, ctx->rsa_n));
1366         CHECK(d0_iobuf_write_bignum(conv, ctx->rsa_e));
1367         CHECK(d0_iobuf_write_bignum(conv, ctx->schnorr_g_to_s));
1368         CHECK(d0_iobuf_close(conv, &sz));
1369         conv = NULL;
1370
1371         n = (*outbuflen / 4) * 3;
1372         if(n > SHA_DIGESTSIZE)
1373                 n = SHA_DIGESTSIZE;
1374         CHECK(d0_iobuf_write_raw(out, sha(shabuf, convbuf, sz), n) == n);
1375         CHECK(d0_iobuf_conv_base64_out(out));
1376
1377         return d0_iobuf_close(out, outbuflen);
1378
1379 fail:
1380         if(conv)
1381                 d0_iobuf_close(conv, &sz);
1382         d0_iobuf_close(out, outbuflen);
1383         return 0;
1384 }
1385
1386 D0_BOOL d0_blind_id_sessionkey_public_id(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
1387 {
1388         D0_BOOL ret;
1389
1390         USINGTEMPS(); // temps: temp0 result
1391         USING(t); USING(other_g_to_t); USING(schnorr_G);
1392
1393         LOCKTEMPS();
1394         CHECK(d0_bignum_mod_pow(temp0, ctx->other_g_to_t, ctx->t, ctx->schnorr_G));
1395         ret = d0_longhash_bignum(temp0, (unsigned char *) outbuf, *outbuflen);
1396         UNLOCKTEMPS();
1397         return ret;
1398
1399 fail:
1400         UNLOCKTEMPS();
1401         return 0;
1402 }
1403
1404 d0_blind_id_t *d0_blind_id_new(void)
1405 {
1406         d0_blind_id_t *b = d0_malloc(sizeof(d0_blind_id_t));
1407         memset(b, 0, sizeof(*b));
1408         return b;
1409 }
1410
1411 void d0_blind_id_free(d0_blind_id_t *a)
1412 {
1413         d0_blind_id_clear(a);
1414         d0_free(a);
1415 }
1416
1417 void d0_blind_id_util_sha256(char *out, const char *in, size_t n)
1418 {
1419         SHA256_CTX context;
1420         SHA256_Init(&context);
1421         SHA256_Update(&context, (const unsigned char *) in, n);
1422         return SHA256_Final((unsigned char *) out, &context);
1423 }
1424
1425 void d0_blind_id_setmallocfuncs(d0_malloc_t *m, d0_free_t *f)
1426 {
1427         d0_setmallocfuncs(m, f);
1428 }
1429 void d0_blind_id_setmutexfuncs(d0_createmutex_t *c, d0_destroymutex_t *d, d0_lockmutex_t *l, d0_unlockmutex_t *u)
1430 {
1431         d0_setmutexfuncs(c, d, l, u);
1432 }