]> de.git.xonotic.org Git - xonotic/d0_blind_id.git/blob - d0_blind_id.c
use pthread library
[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 char *sha(const unsigned char *in, size_t len)
49 {
50         static __thread char h[32];
51         d0_blind_id_util_sha256(h, (const char *) in, len);
52         return h;
53 }
54
55 // for zero knowledge, we need multiple instances of schnorr ID scheme... should normally be sequential
56 // parallel schnorr ID is not provably zero knowledge :(
57 //   (evil verifier can know all questions in advance, so sequential is disadvantage for him)
58 // we'll just live with a 1:1048576 chance of cheating, and support reauthenticating
59
60 #define SCHNORR_BITS 20
61 // probability of cheat: 2^(-bits+1)
62
63 #define SCHNORR_HASHSIZE SHA_DIGESTSIZE
64 // cannot be >= SHA_DIGESTSIZE
65 // *8 must be >= SCHNORR_BITS
66 // no need to save bits here
67
68 #define MSGSIZE 640 // ought to be enough for anyone
69
70 struct d0_blind_id_s
71 {
72         // signing (Xonotic pub and priv key)
73         d0_bignum_t *rsa_n, *rsa_e, *rsa_d;
74
75         // public data (Schnorr ID)
76         d0_bignum_t *schnorr_G;
77
78         // private data (player ID private key)
79         d0_bignum_t *schnorr_s;
80
81         // public data (player ID public key, this is what the server gets to know)
82         d0_bignum_t *schnorr_g_to_s;
83         d0_bignum_t *schnorr_H_g_to_s_signature; // 0 when signature is invalid
84         // as hash function H, we get the SHA1 and reinterpret as bignum - yes, it always is < 160 bits
85
86         // temp data
87         d0_bignum_t *rsa_blind_signature_camouflage; // random number blind signature
88
89         d0_bignum_t *r; // random number for schnorr ID
90         d0_bignum_t *t; // for DH key exchange
91         d0_bignum_t *g_to_t; // for DH key exchange
92         d0_bignum_t *other_g_to_t; // for DH key exchange
93         d0_bignum_t *challenge; // challenge
94
95         char msghash[SCHNORR_HASHSIZE]; // init hash
96         char msg[MSGSIZE]; // message
97         size_t msglen; // message length
98 };
99
100 //#define CHECKDEBUG
101 #ifdef CHECKDEBUG
102 #define CHECK(x) do { if(!(x)) { fprintf(stderr, "CHECK FAILED (%s:%d): %s\n", __FILE__, __LINE__, #x); goto fail; } } while(0)
103 #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)
104 #else
105 #define CHECK(x) do { if(!(x)) goto fail; } while(0)
106 #define CHECK_ASSIGN(var, value) do { d0_bignum_t *val; val = value; if(!val) goto fail; var = val; } while(0)
107 #endif
108
109 #define USING(x) if(!(ctx->x)) return 0
110 #define REPLACING(x)
111
112 // safe to use
113 static d0_bignum_t *zero, *one, *four;
114
115 static d0_bignum_t *temp0, *temp1, *temp2, *temp3, *temp4;
116 static void *tempmutex = NULL; // hold this mutex when using temp0 to temp4
117 #define USINGTEMPS() int locked = 0
118 #define LOCKTEMPS() do { if(!locked) d0_lockmutex(tempmutex); locked = 1; } while(0)
119 #define UNLOCKTEMPS() do { if(locked) d0_unlockmutex(tempmutex); locked = 0; } while(0);
120
121 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_INITIALIZE(void)
122 {
123         USINGTEMPS();
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
371         n = outbuflen;
372         while(n > SHA_DIGESTSIZE)
373         {
374                 memcpy(outbuf, sha(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(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         static __thread 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         static __thread unsigned char convbuf[2048];
535         d0_iobuf_t *conv = NULL;
536         size_t sz, n;
537
538         USING(rsa_n); USING(rsa_e);
539
540         out = d0_iobuf_open_write(outbuf, *outbuflen);
541         conv = d0_iobuf_open_write(convbuf, sizeof(convbuf));
542
543         CHECK(d0_iobuf_write_bignum(conv, ctx->rsa_n));
544         CHECK(d0_iobuf_write_bignum(conv, ctx->rsa_e));
545         CHECK(d0_iobuf_close(conv, &sz));
546         conv = NULL;
547
548         n = (*outbuflen / 4) * 3;
549         if(n > SHA_DIGESTSIZE)
550                 n = SHA_DIGESTSIZE;
551         CHECK(d0_iobuf_write_raw(out, sha(convbuf, sz), n) == n);
552         CHECK(d0_iobuf_conv_base64_out(out));
553
554         return d0_iobuf_close(out, outbuflen);
555
556 fail:
557         if(conv)
558                 d0_iobuf_close(conv, &sz);
559         d0_iobuf_close(out, outbuflen);
560         return 0;
561 }
562
563 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_generate_private_id_modulus(d0_blind_id_t *ctx)
564 {
565         USING(rsa_n);
566         REPLACING(schnorr_G);
567
568         CHECK_ASSIGN(ctx->schnorr_G, d0_bignum_zero(ctx->schnorr_G));
569         CHECK(d0_dl_generate_key(d0_bignum_size(ctx->rsa_n)-1, ctx->schnorr_G));
570         return 1;
571 fail:
572         return 0;
573 }
574
575 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_read_private_id_modulus(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
576 {
577         d0_iobuf_t *in = NULL;
578
579         REPLACING(schnorr_G);
580
581         in = d0_iobuf_open_read(inbuf, inbuflen);
582         CHECK_ASSIGN(ctx->schnorr_G, d0_iobuf_read_bignum(in, ctx->schnorr_G));
583         return d0_iobuf_close(in, NULL);
584
585 fail:
586         d0_iobuf_close(in, NULL);
587         return 0;
588 }
589
590 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_write_private_id_modulus(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
591 {
592         d0_iobuf_t *out = NULL;
593
594         USING(schnorr_G);
595
596         out = d0_iobuf_open_write(outbuf, *outbuflen);
597         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_G));
598         return d0_iobuf_close(out, outbuflen);
599
600 fail:
601         d0_iobuf_close(out, outbuflen);
602         return 0;
603 }
604
605 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_generate_private_id_start(d0_blind_id_t *ctx)
606 {
607         USINGTEMPS(); // temps: temp0 = order
608         USING(schnorr_G);
609         REPLACING(schnorr_s); REPLACING(schnorr_g_to_s);
610
611         LOCKTEMPS();
612         CHECK(d0_dl_get_order(temp0, ctx->schnorr_G));
613         CHECK_ASSIGN(ctx->schnorr_s, d0_bignum_rand_range(ctx->schnorr_s, zero, temp0));
614         CHECK_ASSIGN(ctx->schnorr_g_to_s, d0_bignum_mod_pow(ctx->schnorr_g_to_s, four, ctx->schnorr_s, ctx->schnorr_G));
615         CHECK_ASSIGN(ctx->schnorr_H_g_to_s_signature, d0_bignum_zero(ctx->schnorr_H_g_to_s_signature));
616         UNLOCKTEMPS();
617         return 1;
618
619 fail:
620         UNLOCKTEMPS();
621         return 0;
622 }
623
624 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_generate_private_id_request(d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
625 {
626         d0_iobuf_t *out = NULL;
627         static __thread unsigned char shabuf[2048];
628         size_t sz;
629
630         USINGTEMPS(); // temps: temp0 rsa_blind_signature_camouflage^challenge, temp1 (4^s)*rsa_blind_signature_camouflage^challenge
631         USING(rsa_n); USING(rsa_e); USING(schnorr_g_to_s);
632         REPLACING(rsa_blind_signature_camouflage);
633
634         out = d0_iobuf_open_write(outbuf, *outbuflen);
635
636         CHECK_ASSIGN(ctx->rsa_blind_signature_camouflage, d0_bignum_rand_bit_atmost(ctx->rsa_blind_signature_camouflage, d0_bignum_size(ctx->rsa_n)));
637         CHECK(d0_bignum_mod_pow(temp0, ctx->rsa_blind_signature_camouflage, ctx->rsa_e, ctx->rsa_n));
638
639         // we will actually sign HA(4^s) to prevent a malleability attack!
640         LOCKTEMPS();
641         CHECK(d0_bignum_mov(temp2, ctx->schnorr_g_to_s));
642         sz = (d0_bignum_size(ctx->rsa_n) + 7) / 8; // this is too long, so we have to take the value % rsa_n when "decrypting"
643         if(sz > sizeof(shabuf))
644                 sz = sizeof(shabuf);
645         CHECK(d0_longhash_bignum(temp2, shabuf, sz));
646         CHECK(d0_bignum_import_unsigned(temp2, shabuf, sz));
647
648         // hash complete
649         CHECK(d0_bignum_mod_mul(temp1, temp2, temp0, ctx->rsa_n));
650         CHECK(d0_iobuf_write_bignum(out, temp1));
651         UNLOCKTEMPS();
652         return d0_iobuf_close(out, outbuflen);
653
654 fail:
655         UNLOCKTEMPS();
656         d0_iobuf_close(out, outbuflen);
657         return 0;
658 }
659
660 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)
661 {
662         d0_iobuf_t *in = NULL;
663         d0_iobuf_t *out = NULL;
664
665         USINGTEMPS(); // temps: temp0 input, temp1 temp0^d
666         USING(rsa_d); USING(rsa_n);
667
668         in = d0_iobuf_open_read(inbuf, inbuflen);
669         out = d0_iobuf_open_write(outbuf, *outbuflen);
670
671         LOCKTEMPS();
672         CHECK(d0_iobuf_read_bignum(in, temp0));
673         CHECK(d0_bignum_mod_pow(temp1, temp0, ctx->rsa_d, ctx->rsa_n));
674         CHECK(d0_iobuf_write_bignum(out, temp1));
675
676         UNLOCKTEMPS();
677         d0_iobuf_close(in, NULL);
678         return d0_iobuf_close(out, outbuflen);
679
680 fail:
681         UNLOCKTEMPS();
682         d0_iobuf_close(in, NULL);
683         d0_iobuf_close(out, outbuflen);
684         return 0;
685 }
686
687 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_finish_private_id_request(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
688 {
689         d0_iobuf_t *in = NULL;
690
691         USINGTEMPS(); // temps: temp0 input, temp1 rsa_blind_signature_camouflage^-1
692         USING(rsa_blind_signature_camouflage); USING(rsa_n);
693         REPLACING(schnorr_H_g_to_s_signature);
694
695         in = d0_iobuf_open_read(inbuf, inbuflen);
696
697         LOCKTEMPS();
698
699         CHECK(d0_iobuf_read_bignum(in, temp0));
700         CHECK(d0_bignum_mod_inv(temp1, ctx->rsa_blind_signature_camouflage, ctx->rsa_n));
701         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));
702
703         UNLOCKTEMPS();
704         return d0_iobuf_close(in, NULL);
705
706 fail:
707         UNLOCKTEMPS();
708         d0_iobuf_close(in, NULL);
709         return 0;
710 }
711
712 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)
713 {
714         d0_iobuf_t *in = NULL;
715
716         REPLACING(rsa_blind_signature_camouflage);
717
718         in = d0_iobuf_open_read(inbuf, inbuflen);
719
720         CHECK_ASSIGN(ctx->rsa_blind_signature_camouflage, d0_iobuf_read_bignum(in, ctx->rsa_blind_signature_camouflage));
721
722         return d0_iobuf_close(in, NULL);
723
724 fail:
725         d0_iobuf_close(in, NULL);
726         return 0;
727 }
728
729 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)
730 {
731         d0_iobuf_t *out = NULL;
732
733         USING(rsa_blind_signature_camouflage);
734
735         out = d0_iobuf_open_write(outbuf, *outbuflen);
736
737         CHECK(d0_iobuf_write_bignum(out, ctx->rsa_blind_signature_camouflage));
738
739         return d0_iobuf_close(out, outbuflen);
740
741 fail:
742         d0_iobuf_close(out, outbuflen);
743         return 0;
744 }
745
746 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_read_private_id(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
747 {
748         d0_iobuf_t *in = NULL;
749
750         REPLACING(schnorr_s); REPLACING(schnorr_g_to_s); REPLACING(schnorr_H_g_to_s_signature);
751
752         in = d0_iobuf_open_read(inbuf, inbuflen);
753
754         CHECK_ASSIGN(ctx->schnorr_s, d0_iobuf_read_bignum(in, ctx->schnorr_s));
755         CHECK_ASSIGN(ctx->schnorr_g_to_s, d0_iobuf_read_bignum(in, ctx->schnorr_g_to_s));
756         CHECK_ASSIGN(ctx->schnorr_H_g_to_s_signature, d0_iobuf_read_bignum(in, ctx->schnorr_H_g_to_s_signature));
757
758         return d0_iobuf_close(in, NULL);
759
760 fail:
761         d0_iobuf_close(in, NULL);
762         return 0;
763 }
764
765 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_read_public_id(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
766 {
767         d0_iobuf_t *in = NULL;
768
769         REPLACING(schnorr_g_to_s); REPLACING(schnorr_H_g_to_s_signature);
770
771         in = d0_iobuf_open_read(inbuf, inbuflen);
772
773         CHECK_ASSIGN(ctx->schnorr_g_to_s, d0_iobuf_read_bignum(in, ctx->schnorr_g_to_s));
774         CHECK_ASSIGN(ctx->schnorr_H_g_to_s_signature, d0_iobuf_read_bignum(in, ctx->schnorr_H_g_to_s_signature));
775
776         return d0_iobuf_close(in, NULL);
777
778 fail:
779         d0_iobuf_close(in, NULL);
780         return 0;
781 }
782
783 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_write_private_id(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
784 {
785         d0_iobuf_t *out = NULL;
786
787         USING(schnorr_s); USING(schnorr_g_to_s); USING(schnorr_H_g_to_s_signature);
788
789         out = d0_iobuf_open_write(outbuf, *outbuflen);
790
791         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_s));
792         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_g_to_s));
793         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_H_g_to_s_signature));
794
795         return d0_iobuf_close(out, outbuflen);
796
797 fail:
798         d0_iobuf_close(out, outbuflen);
799         return 0;
800 }
801
802 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_write_public_id(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
803 {
804         d0_iobuf_t *out = NULL;
805
806         USING(schnorr_g_to_s); USING(schnorr_H_g_to_s_signature);
807
808         out = d0_iobuf_open_write(outbuf, *outbuflen);
809
810         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_g_to_s));
811         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_H_g_to_s_signature));
812
813         return d0_iobuf_close(out, outbuflen);
814
815 fail:
816         d0_iobuf_close(out, outbuflen);
817         return 0;
818 }
819
820 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)
821 // start =
822 //   first run: send 4^s, 4^s signature
823 //   1. get random r, send HASH(4^r)
824 {
825         d0_iobuf_t *out = NULL;
826         static __thread unsigned char convbuf[1024];
827         d0_iobuf_t *conv = NULL;
828         size_t sz = 0;
829         D0_BOOL failed = 0;
830
831         USINGTEMPS(); // temps: temp0 order, temp0 4^r
832         if(is_first)
833         {
834                 USING(schnorr_g_to_s); USING(schnorr_H_g_to_s_signature);
835         }
836         USING(schnorr_G);
837         REPLACING(r); REPLACING(t); REPLACING(g_to_t);
838
839         out = d0_iobuf_open_write(outbuf, *outbuflen);
840
841         if(is_first)
842         {
843                 // send ID
844                 if(send_modulus)
845                         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_G));
846                 CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_g_to_s));
847                 CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_H_g_to_s_signature));
848         }
849
850         // start schnorr ID scheme
851         // generate random number r; x = g^r; send hash of x, remember r, forget x
852         LOCKTEMPS();
853         CHECK(d0_dl_get_order(temp0, ctx->schnorr_G));
854 #ifdef RNG_XKCD
855         CHECK_ASSIGN(ctx->r, d0_bignum_int(ctx->r, 4)); // decided by fair dice roll
856 #else
857         CHECK_ASSIGN(ctx->r, d0_bignum_rand_range(ctx->r, zero, temp0));
858 #endif
859
860         // initialize Signed Diffie Hellmann
861         // we already have the group order in temp1
862 #ifdef RNG_XKCD
863         CHECK_ASSIGN(ctx->t, d0_bignum_int(ctx->t, 4)); // decided by fair dice roll
864 #else
865         CHECK_ASSIGN(ctx->t, d0_bignum_rand_range(ctx->t, zero, temp0));
866 #endif
867         // can we SOMEHOW do this with just one mod_pow?
868
869         CHECK(d0_bignum_mod_pow(temp0, four, ctx->r, ctx->schnorr_G));
870         CHECK_ASSIGN(ctx->g_to_t, d0_bignum_mod_pow(ctx->g_to_t, four, ctx->t, ctx->schnorr_G));
871         CHECK(!failed);
872
873         // hash it, hash it, everybody hash it
874         conv = d0_iobuf_open_write(convbuf, sizeof(convbuf));
875         CHECK(d0_iobuf_write_bignum(conv, temp0));
876         CHECK(d0_iobuf_write_bignum(conv, ctx->g_to_t));
877         CHECK(d0_iobuf_write_packet(conv, msg, msglen));
878         CHECK(d0_iobuf_write_bignum(conv, temp0));
879         UNLOCKTEMPS();
880         CHECK(d0_iobuf_write_bignum(conv, ctx->g_to_t));
881         d0_iobuf_close(conv, &sz);
882         conv = NULL;
883         CHECK(d0_iobuf_write_raw(out, sha(convbuf, sz), SCHNORR_HASHSIZE) == SCHNORR_HASHSIZE);
884         CHECK(d0_iobuf_write_packet(out, msg, msglen));
885
886         return d0_iobuf_close(out, outbuflen);
887
888 fail:
889         UNLOCKTEMPS();
890         d0_iobuf_close(out, outbuflen);
891         return 0;
892 }
893
894 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)
895 //   first run: get 4^s, 4^s signature
896 //   1. check sig
897 //   2. save HASH(4^r)
898 //   3. send challenge challenge of SCHNORR_BITS
899 {
900         d0_iobuf_t *in = NULL;
901         d0_iobuf_t *out = NULL;
902         static __thread unsigned char shabuf[2048];
903         size_t sz;
904
905         USINGTEMPS(); // temps: temp0 order, temp0 signature check
906         if(is_first)
907         {
908                 REPLACING(schnorr_g_to_s); REPLACING(schnorr_H_g_to_s_signature);
909                 if(recv_modulus)
910                         REPLACING(schnorr_G);
911                 else
912                         USING(schnorr_G);
913         }
914         else
915         {
916                 USING(schnorr_g_to_s); USING(schnorr_H_g_to_s_signature);
917                 USING(schnorr_G);
918         }
919         USING(rsa_e); USING(rsa_n);
920         REPLACING(challenge); REPLACING(msg); REPLACING(msglen); REPLACING(msghash); REPLACING(r); REPLACING(t);
921
922         in = d0_iobuf_open_read(inbuf, inbuflen);
923         out = d0_iobuf_open_write(outbuf, *outbuflen);
924
925         if(is_first)
926         {
927                 if(recv_modulus)
928                 {
929                         CHECK_ASSIGN(ctx->schnorr_G, d0_iobuf_read_bignum(in, ctx->schnorr_G));
930                         CHECK(d0_bignum_cmp(ctx->schnorr_G, zero) > 0);
931                         CHECK(d0_bignum_cmp(ctx->schnorr_G, ctx->rsa_n) < 0);
932                 }
933                 CHECK_ASSIGN(ctx->schnorr_g_to_s, d0_iobuf_read_bignum(in, ctx->schnorr_g_to_s));
934                 CHECK(d0_bignum_cmp(ctx->schnorr_g_to_s, zero) >= 0);
935                 CHECK(d0_bignum_cmp(ctx->schnorr_g_to_s, ctx->schnorr_G) < 0);
936                 CHECK_ASSIGN(ctx->schnorr_H_g_to_s_signature, d0_iobuf_read_bignum(in, ctx->schnorr_H_g_to_s_signature));
937                 CHECK(d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, zero) >= 0);
938                 CHECK(d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, ctx->rsa_n) < 0);
939
940                 // check signature of key (t = k^d, so, t^challenge = k)
941                 LOCKTEMPS();
942                 CHECK(d0_bignum_mod_pow(temp0, ctx->schnorr_H_g_to_s_signature, ctx->rsa_e, ctx->rsa_n));
943
944                 // we will actually sign SHA(4^s) to prevent a malleability attack!
945                 CHECK(d0_bignum_mov(temp2, ctx->schnorr_g_to_s));
946                 sz = (d0_bignum_size(ctx->rsa_n) + 7) / 8; // this is too long, so we have to take the value % rsa_n when "decrypting"
947                 if(sz > sizeof(shabuf))
948                         sz = sizeof(shabuf);
949                 CHECK(d0_longhash_bignum(temp2, shabuf, sz));
950                 CHECK(d0_bignum_import_unsigned(temp2, shabuf, sz));
951
952                 // + 7 / 8 is too large, so let's mod it
953                 CHECK(d0_bignum_divmod(NULL, temp1, temp2, ctx->rsa_n));
954
955                 // hash complete
956                 if(d0_bignum_cmp(temp0, temp1))
957                 {
958                         // accept the key anyway, but mark as failed signature! will later return 0 in status
959                         CHECK(d0_bignum_zero(ctx->schnorr_H_g_to_s_signature));
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         static __thread unsigned char convbuf[1024];
1055         d0_iobuf_t *conv = NULL;
1056         size_t sz;
1057
1058         USINGTEMPS(); // temps: 0 y 1 order
1059         USING(challenge); USING(schnorr_G);
1060         REPLACING(other_g_to_t);
1061
1062         in = d0_iobuf_open_read(inbuf, inbuflen);
1063
1064         LOCKTEMPS();
1065
1066         CHECK(d0_dl_get_order(temp1, ctx->schnorr_G));
1067         CHECK(d0_iobuf_read_bignum(in, temp0));
1068         CHECK(d0_bignum_cmp(temp0, zero) >= 0);
1069         CHECK(d0_bignum_cmp(temp0, temp1) < 0);
1070
1071         // verify schnorr ID scheme
1072 #ifdef D0_BLIND_ID_POSITIVE_PROTOCOL
1073         // we need 4^r = 4^temp0 (g^s)^-challenge
1074         CHECK(d0_bignum_mod_inv(temp1, ctx->schnorr_g_to_s, ctx->schnorr_G));
1075         CHECK(d0_bignum_mod_pow(temp2, temp1, ctx->challenge, ctx->schnorr_G));
1076 #else
1077         // we need 4^r = 4^temp0 (g^s)^challenge
1078         CHECK(d0_bignum_mod_pow(temp2, ctx->schnorr_g_to_s, ctx->challenge, ctx->schnorr_G));
1079 #endif
1080         CHECK(d0_bignum_mod_pow(temp1, four, temp0, ctx->schnorr_G));
1081         CHECK_ASSIGN(temp3, d0_bignum_mod_mul(temp3, temp1, temp2, ctx->schnorr_G));
1082
1083         // Diffie Hellmann recv
1084         CHECK_ASSIGN(ctx->other_g_to_t, d0_iobuf_read_bignum(in, ctx->other_g_to_t));
1085         CHECK(d0_bignum_cmp(ctx->other_g_to_t, zero) > 0);
1086         CHECK(d0_bignum_cmp(ctx->other_g_to_t, ctx->schnorr_G) < 0);
1087
1088         // hash it, hash it, everybody hash it
1089         conv = d0_iobuf_open_write(convbuf, sizeof(convbuf));
1090         CHECK(d0_iobuf_write_bignum(conv, temp3));
1091         CHECK(d0_iobuf_write_bignum(conv, ctx->other_g_to_t));
1092         CHECK(d0_iobuf_write_packet(conv, ctx->msg, ctx->msglen));
1093         CHECK(d0_iobuf_write_bignum(conv, temp3));
1094         UNLOCKTEMPS();
1095         CHECK(d0_iobuf_write_bignum(conv, ctx->other_g_to_t));
1096         d0_iobuf_close(conv, &sz);
1097         conv = NULL;
1098         if(memcmp(sha(convbuf, sz), ctx->msghash, SCHNORR_HASHSIZE))
1099         {
1100                 // FAIL (not owned by player)
1101                 goto fail;
1102         }
1103
1104         if(status)
1105                 *status = !!d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, zero);
1106
1107         if(ctx->msglen <= *msglen)
1108                 memcpy(msg, ctx->msg, ctx->msglen);
1109         else
1110                 memcpy(msg, ctx->msg, *msglen);
1111         *msglen = ctx->msglen;
1112
1113         d0_iobuf_close(in, NULL);
1114         return 1;
1115
1116 fail:
1117         UNLOCKTEMPS();
1118         d0_iobuf_close(in, NULL);
1119         return 0;
1120 }
1121
1122 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_authenticate_with_private_id_generate_missing_signature(d0_blind_id_t *ctx)
1123 {
1124         size_t sz;
1125         static __thread unsigned char shabuf[2048];
1126
1127         USINGTEMPS(); // temps: 2 hash
1128         REPLACING(schnorr_H_g_to_s_signature);
1129         USING(schnorr_g_to_s); USING(rsa_d); USING(rsa_n);
1130
1131         LOCKTEMPS();
1132
1133         // we will actually sign SHA(4^s) to prevent a malleability attack!
1134         sz = (d0_bignum_size(ctx->rsa_n) + 7) / 8; // this is too long, so we have to take the value % rsa_n when "decrypting"
1135         if(sz > sizeof(shabuf))
1136                 sz = sizeof(shabuf);
1137         CHECK(d0_longhash_bignum(ctx->schnorr_g_to_s, shabuf, sz));
1138         LOCKTEMPS();
1139         CHECK(d0_bignum_import_unsigned(temp2, shabuf, sz));
1140
1141         // + 7 / 8 is too large, so let's mod it
1142         CHECK(d0_bignum_divmod(NULL, temp1, temp2, ctx->rsa_n));
1143         CHECK(d0_bignum_mod_pow(ctx->schnorr_H_g_to_s_signature, temp1, ctx->rsa_d, ctx->rsa_n));
1144
1145         UNLOCKTEMPS();
1146         return 1;
1147
1148 fail:
1149         UNLOCKTEMPS();
1150         return 0;
1151 }
1152
1153 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)
1154 {
1155         d0_iobuf_t *out = NULL;
1156         unsigned char *convbuf = NULL;
1157         static __thread unsigned char shabuf[2048];
1158         d0_iobuf_t *conv = NULL;
1159         size_t sz = 0;
1160
1161         USINGTEMPS(); // temps: 0 order 1 4^r 2 hash
1162         if(is_first)
1163         {
1164                 USING(schnorr_g_to_s); USING(schnorr_H_g_to_s_signature);
1165         }
1166         USING(schnorr_G);
1167         USING(schnorr_s);
1168         REPLACING(r);
1169
1170         out = d0_iobuf_open_write(outbuf, *outbuflen);
1171
1172         if(is_first)
1173         {
1174                 // send ID
1175                 if(send_modulus)
1176                         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_G));
1177                 CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_g_to_s));
1178                 CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_H_g_to_s_signature));
1179         }
1180
1181         // start schnorr SIGNATURE scheme
1182         // generate random number r; x = g^r; send hash of H(m||r), remember r, forget x
1183         LOCKTEMPS();
1184         CHECK(d0_dl_get_order(temp0, ctx->schnorr_G));
1185         CHECK_ASSIGN(ctx->r, d0_bignum_rand_range(ctx->r, zero, temp0));
1186         CHECK(d0_bignum_mod_pow(temp1, four, ctx->r, ctx->schnorr_G));
1187
1188         // hash it, hash it, everybody hash it
1189         conv = d0_iobuf_open_write_p((void **) &convbuf, 0);
1190         CHECK(d0_iobuf_write_packet(conv, message, msglen));
1191         CHECK(d0_iobuf_write_bignum(conv, temp1));
1192         d0_iobuf_close(conv, &sz);
1193         conv = NULL;
1194         CHECK(d0_longhash_destructive(convbuf, sz, shabuf, (d0_bignum_size(temp0) + 7) / 8));
1195         d0_free(convbuf);
1196         convbuf = NULL;
1197         CHECK(d0_bignum_import_unsigned(temp2, shabuf, (d0_bignum_size(temp0) + 7) / 8));
1198         CHECK(d0_iobuf_write_bignum(out, temp2));
1199
1200         // multiply with secret, sub k, modulo order
1201         CHECK(d0_bignum_mod_mul(temp1, temp2, ctx->schnorr_s, temp0));
1202 #ifdef D0_BLIND_ID_POSITIVE_PROTOCOL
1203         CHECK(d0_bignum_mod_add(temp2, ctx->r, temp1, temp0));
1204 #else
1205         CHECK(d0_bignum_mod_sub(temp2, ctx->r, temp1, temp0));
1206 #endif
1207         CHECK(d0_iobuf_write_bignum(out, temp2));
1208         UNLOCKTEMPS();
1209
1210         // write the message itself
1211         if(with_msg)
1212                 CHECK(d0_iobuf_write_packet(out, message, msglen));
1213
1214         return d0_iobuf_close(out, outbuflen);
1215
1216 fail:
1217         UNLOCKTEMPS();
1218         d0_iobuf_close(out, outbuflen);
1219         return 0;
1220 }
1221 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)
1222 {
1223         return d0_blind_id_sign_with_private_id_sign_internal(ctx, is_first, send_modulus, 1, message, msglen, outbuf, outbuflen);
1224 }
1225 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)
1226 {
1227         return d0_blind_id_sign_with_private_id_sign_internal(ctx, is_first, send_modulus, 0, message, msglen, outbuf, outbuflen);
1228 }
1229
1230 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)
1231 {
1232         d0_iobuf_t *in = NULL;
1233         d0_iobuf_t *conv = NULL;
1234         unsigned char *convbuf = NULL;
1235         static __thread unsigned char shabuf[2048];
1236         size_t sz;
1237
1238         USINGTEMPS(); // temps: 0 sig^e 2 g^s 3 g^-s 4 order
1239         if(is_first)
1240         {
1241                 REPLACING(schnorr_g_to_s); REPLACING(schnorr_H_g_to_s_signature);
1242                 if(recv_modulus)
1243                         REPLACING(schnorr_G);
1244                 else
1245                         USING(schnorr_G);
1246         }
1247         else
1248         {
1249                 USING(schnorr_g_to_s); USING(schnorr_H_g_to_s_signature);
1250                 USING(schnorr_G);
1251         }
1252         USING(rsa_e); USING(rsa_n);
1253
1254         in = d0_iobuf_open_read(inbuf, inbuflen);
1255
1256         if(is_first)
1257         {
1258                 if(recv_modulus)
1259                 {
1260                         CHECK_ASSIGN(ctx->schnorr_G, d0_iobuf_read_bignum(in, ctx->schnorr_G));
1261                         CHECK(d0_bignum_cmp(ctx->schnorr_G, zero) > 0);
1262                         CHECK(d0_bignum_cmp(ctx->schnorr_G, ctx->rsa_n) < 0);
1263                 }
1264                 CHECK_ASSIGN(ctx->schnorr_g_to_s, d0_iobuf_read_bignum(in, ctx->schnorr_g_to_s));
1265                 CHECK(d0_bignum_cmp(ctx->schnorr_g_to_s, zero) >= 0);
1266                 CHECK(d0_bignum_cmp(ctx->schnorr_g_to_s, ctx->schnorr_G) < 0);
1267                 CHECK_ASSIGN(ctx->schnorr_H_g_to_s_signature, d0_iobuf_read_bignum(in, ctx->schnorr_H_g_to_s_signature));
1268                 CHECK(d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, zero) >= 0);
1269                 CHECK(d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, ctx->rsa_n) < 0);
1270
1271                 // check signature of key (t = k^d, so, t^challenge = k)
1272                 LOCKTEMPS();
1273                 CHECK(d0_bignum_mod_pow(temp0, ctx->schnorr_H_g_to_s_signature, ctx->rsa_e, ctx->rsa_n));
1274
1275                 // we will actually sign SHA(4^s) to prevent a malleability attack!
1276                 sz = (d0_bignum_size(ctx->rsa_n) + 7) / 8; // this is too long, so we have to take the value % rsa_n when "decrypting"
1277                 if(sz > sizeof(shabuf))
1278                         sz = sizeof(shabuf);
1279                 CHECK(d0_longhash_bignum(ctx->schnorr_g_to_s, shabuf, sz));
1280                 CHECK(d0_bignum_import_unsigned(temp2, shabuf, sz));
1281
1282                 // + 7 / 8 is too large, so let's mod it
1283                 CHECK(d0_bignum_divmod(NULL, temp1, temp2, ctx->rsa_n));
1284
1285                 // hash complete
1286                 if(d0_bignum_cmp(temp0, temp1))
1287                 {
1288                         // accept the key anyway, but mark as failed signature! will later return 0 in status
1289                         CHECK(d0_bignum_zero(ctx->schnorr_H_g_to_s_signature));
1290                 }
1291         }
1292
1293         CHECK(d0_dl_get_order(temp4, ctx->schnorr_G));
1294         CHECK(d0_iobuf_read_bignum(in, temp0)); // e == H(m || g^r)
1295         CHECK(d0_iobuf_read_bignum(in, temp1)); // x == (r - s*e) mod |G|
1296         if(with_msg)
1297                 CHECK(d0_iobuf_read_packet(in, msg, msglen));
1298
1299         // VERIFY: g^x * (g^s)^-e = g^(x - s*e) = g^r
1300
1301         // verify schnorr ID scheme
1302         // we need g^r = g^x (g^s)^e
1303         CHECK(d0_bignum_mod_pow(temp2, four, temp1, ctx->schnorr_G));
1304 #ifdef D0_BLIND_ID_POSITIVE_PROTOCOL
1305         CHECK(d0_bignum_mod_inv(temp3, ctx->schnorr_g_to_s, ctx->schnorr_G));
1306         CHECK(d0_bignum_mod_pow(temp1, temp3, temp0, ctx->schnorr_G));
1307 #else
1308         CHECK(d0_bignum_mod_pow(temp1, ctx->schnorr_g_to_s, temp0, ctx->schnorr_G));
1309 #endif
1310         CHECK_ASSIGN(temp3, d0_bignum_mod_mul(temp3, temp1, temp2, ctx->schnorr_G)); // temp3 now is g^r
1311
1312         // hash it, hash it, everybody hash it
1313         conv = d0_iobuf_open_write_p((void **) &convbuf, 0);
1314         CHECK(d0_iobuf_write_packet(conv, msg, *msglen));
1315         CHECK(d0_iobuf_write_bignum(conv, temp3));
1316         d0_iobuf_close(conv, &sz);
1317         conv = NULL;
1318         CHECK(d0_longhash_destructive(convbuf, sz, shabuf, (d0_bignum_size(temp4) + 7) / 8));
1319         d0_free(convbuf);
1320         convbuf = NULL;
1321         CHECK(d0_bignum_import_unsigned(temp1, shabuf, (d0_bignum_size(temp4) + 7) / 8));
1322
1323         // verify signature
1324         CHECK(!d0_bignum_cmp(temp0, temp1));
1325         UNLOCKTEMPS();
1326
1327         if(status)
1328                 *status = !!d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, zero);
1329
1330         d0_iobuf_close(in, NULL);
1331         return 1;
1332
1333 fail:
1334         UNLOCKTEMPS();
1335         d0_iobuf_close(in, NULL);
1336         return 0;
1337 }
1338 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)
1339 {
1340         return d0_blind_id_sign_with_private_id_verify_internal(ctx, is_first, recv_modulus, 1, inbuf, inbuflen, msg, msglen, status);
1341 }
1342 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)
1343 {
1344         return d0_blind_id_sign_with_private_id_verify_internal(ctx, is_first, recv_modulus, 0, inbuf, inbuflen, (char *) msg, &msglen, status);
1345 }
1346
1347 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_fingerprint64_public_id(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
1348 {
1349         d0_iobuf_t *out = NULL;
1350         static __thread unsigned char convbuf[1024];
1351         d0_iobuf_t *conv = NULL;
1352         size_t sz, n;
1353
1354         USING(rsa_n);
1355         USING(rsa_e);
1356         USING(schnorr_g_to_s);
1357
1358         out = d0_iobuf_open_write(outbuf, *outbuflen);
1359         conv = d0_iobuf_open_write(convbuf, sizeof(convbuf));
1360
1361         CHECK(d0_iobuf_write_bignum(conv, ctx->rsa_n));
1362         CHECK(d0_iobuf_write_bignum(conv, ctx->rsa_e));
1363         CHECK(d0_iobuf_write_bignum(conv, ctx->schnorr_g_to_s));
1364         CHECK(d0_iobuf_close(conv, &sz));
1365         conv = NULL;
1366
1367         n = (*outbuflen / 4) * 3;
1368         if(n > SHA_DIGESTSIZE)
1369                 n = SHA_DIGESTSIZE;
1370         CHECK(d0_iobuf_write_raw(out, sha(convbuf, sz), n) == n);
1371         CHECK(d0_iobuf_conv_base64_out(out));
1372
1373         return d0_iobuf_close(out, outbuflen);
1374
1375 fail:
1376         if(conv)
1377                 d0_iobuf_close(conv, &sz);
1378         d0_iobuf_close(out, outbuflen);
1379         return 0;
1380 }
1381
1382 D0_BOOL d0_blind_id_sessionkey_public_id(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
1383 {
1384         D0_BOOL ret;
1385
1386         USINGTEMPS(); // temps: temp0 result
1387         USING(t); USING(other_g_to_t); USING(schnorr_G);
1388
1389         LOCKTEMPS();
1390         CHECK(d0_bignum_mod_pow(temp0, ctx->other_g_to_t, ctx->t, ctx->schnorr_G));
1391         ret = d0_longhash_bignum(temp0, (unsigned char *) outbuf, *outbuflen);
1392         UNLOCKTEMPS();
1393         return ret;
1394
1395 fail:
1396         UNLOCKTEMPS();
1397         return 0;
1398 }
1399
1400 d0_blind_id_t *d0_blind_id_new(void)
1401 {
1402         d0_blind_id_t *b = d0_malloc(sizeof(d0_blind_id_t));
1403         memset(b, 0, sizeof(*b));
1404         return b;
1405 }
1406
1407 void d0_blind_id_free(d0_blind_id_t *a)
1408 {
1409         d0_blind_id_clear(a);
1410         d0_free(a);
1411 }
1412
1413 void d0_blind_id_util_sha256(char *out, const char *in, size_t n)
1414 {
1415         SHA256_CTX context;
1416         SHA256_Init(&context);
1417         SHA256_Update(&context, (const unsigned char *) in, n);
1418         return SHA256_Final((unsigned char *) out, &context);
1419 }
1420
1421 void d0_blind_id_setmallocfuncs(d0_malloc_t *m, d0_free_t *f)
1422 {
1423         d0_setmallocfuncs(m, f);
1424 }
1425 void d0_blind_id_setmutexfuncs(d0_createmutex_t *c, d0_destroymutex_t *d, d0_lockmutex_t *l, d0_unlockmutex_t *u)
1426 {
1427         d0_setmutexfuncs(c, d, l, u);
1428 }