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