]> git.xonotic.org Git - xonotic/d0_blind_id.git/blob - d0_blind_id.c
also support signing
[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 // our SHA is SHA-256
44 #define SHA_DIGESTSIZE 32
45 const char *sha(const unsigned char *in, size_t len)
46 {
47         static char h[32];
48         d0_blind_id_util_sha256(h, (const char *) in, len);
49         return h;
50 }
51
52 // for zero knowledge, we need multiple instances of schnorr ID scheme... should normally be sequential
53 // parallel schnorr ID is not provably zero knowledge :(
54 //   (evil verifier can know all questions in advance, so sequential is disadvantage for him)
55 // we'll just live with a 1:1048576 chance of cheating, and support reauthenticating
56
57 #define SCHNORR_BITS 20
58 // probability of cheat: 2^(-bits+1)
59
60 #define SCHNORR_HASHSIZE SHA_DIGESTSIZE
61 // cannot be >= SHA_DIGESTSIZE
62 // *8 must be >= SCHNORR_BITS
63 // no need to save bits here
64
65 #define MSGSIZE 640 // ought to be enough for anyone
66
67 struct d0_blind_id_s
68 {
69         // signing (Xonotic pub and priv key)
70         d0_bignum_t *rsa_n, *rsa_e, *rsa_d;
71
72         // public data (Schnorr ID)
73         d0_bignum_t *schnorr_G;
74
75         // private data (player ID private key)
76         d0_bignum_t *schnorr_s;
77
78         // public data (player ID public key, this is what the server gets to know)
79         d0_bignum_t *schnorr_g_to_s;
80         d0_bignum_t *schnorr_H_g_to_s_signature; // 0 when signature is invalid
81         // as hash function H, we get the SHA1 and reinterpret as bignum - yes, it always is < 160 bits
82
83         // temp data
84         d0_bignum_t *rsa_blind_signature_camouflage; // random number blind signature
85
86         d0_bignum_t *r; // random number for schnorr ID
87         d0_bignum_t *t; // for DH key exchange
88         d0_bignum_t *g_to_t; // for DH key exchange
89         d0_bignum_t *other_g_to_t; // for DH key exchange
90         d0_bignum_t *challenge; // challenge
91
92         char msghash[SCHNORR_HASHSIZE]; // init hash
93         char msg[MSGSIZE]; // message
94         size_t msglen; // message length
95 };
96
97 #define CHECK(x) do { if(!(x)) goto fail; } while(0)
98 #define CHECK_ASSIGN(var, value) do { d0_bignum_t *val; val = value; if(!val) goto fail; var = val; } while(0)
99 #define MPCHECK(x) do { if(!failed) if(!(x)) failed = 1; } while(0)
100 #define MPCHECK_ASSIGN(var, value) do { if(!failed) { d0_bignum_t *val; val = value; if(val) var = val; else failed = 1; } } while(0)
101
102 #define USING(x) if(!(ctx->x)) return 0
103 #define REPLACING(x)
104
105 static d0_bignum_t *zero, *one, *four, *temp0, *temp1, *temp2, *temp3, *temp4;
106
107 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_INITIALIZE(void)
108 {
109         CHECK(d0_bignum_INITIALIZE());
110         CHECK_ASSIGN(zero, d0_bignum_int(zero, 0));
111         CHECK_ASSIGN(one, d0_bignum_int(one, 1));
112         CHECK_ASSIGN(four, d0_bignum_int(four, 4));
113         CHECK_ASSIGN(temp0, d0_bignum_int(temp0, 0));
114         CHECK_ASSIGN(temp1, d0_bignum_int(temp1, 0));
115         CHECK_ASSIGN(temp2, d0_bignum_int(temp2, 0));
116         CHECK_ASSIGN(temp3, d0_bignum_int(temp3, 0));
117         CHECK_ASSIGN(temp4, d0_bignum_int(temp4, 0));
118         return 1;
119 fail:
120         return 0;
121 }
122
123 void d0_blind_id_SHUTDOWN(void)
124 {
125         d0_bignum_free(zero);
126         d0_bignum_free(one);
127         d0_bignum_free(four);
128         d0_bignum_free(temp0);
129         d0_bignum_free(temp1);
130         d0_bignum_free(temp2);
131         d0_bignum_free(temp3);
132         d0_bignum_free(temp4);
133         d0_bignum_SHUTDOWN();
134 }
135
136 // (G-1)/2
137 d0_bignum_t *d0_dl_get_order(d0_bignum_t *o, const d0_bignum_t *G)
138 {
139         CHECK_ASSIGN(o, d0_bignum_sub(o, G, one));
140         CHECK(d0_bignum_shl(o, o, -1)); // order o = (G-1)/2
141         return o;
142 fail:
143         return NULL;
144 }
145 // 2o+1
146 d0_bignum_t *d0_dl_get_from_order(d0_bignum_t *G, const d0_bignum_t *o)
147 {
148         CHECK_ASSIGN(G, d0_bignum_shl(G, o, 1));
149         CHECK(d0_bignum_add(G, G, one));
150         return G;
151 fail:
152         return NULL;
153 }
154
155 D0_BOOL d0_dl_generate_key(size_t size, d0_bignum_t *G)
156 {
157         // using: temp0
158         if(size < 16)
159                 size = 16;
160         for(;;)
161         {
162                 CHECK(d0_bignum_rand_bit_exact(temp0, size-1));
163                 if(d0_bignum_isprime(temp0, 0) == 0)
164                         continue;
165                 CHECK(d0_dl_get_from_order(G, temp0));
166                 if(d0_bignum_isprime(G, 10) == 0)
167                         continue;
168                 if(d0_bignum_isprime(temp0, 10) == 0) // finish the previous test
169                         continue;
170                 break;
171         }
172         return 1;
173 fail:
174         return 0;
175 }
176
177 D0_BOOL d0_rsa_generate_key(size_t size, const d0_bignum_t *challenge, d0_bignum_t *d, d0_bignum_t *n)
178 {
179         // uses temp0 to temp4
180         int fail = 0;
181         int gcdfail = 0;
182         int pb = (size + 1)/2;
183         int qb = size - pb;
184         if(pb < 8)
185                 pb = 8;
186         if(qb < 8)
187                 qb = 8;
188         for (;;)
189         {
190                 CHECK(d0_bignum_rand_bit_exact(temp0, pb));
191                 if(d0_bignum_isprime(temp0, 10) == 0)
192                         continue;
193                 CHECK(d0_bignum_sub(temp2, temp0, one));
194                 CHECK(d0_bignum_gcd(temp4, NULL, NULL, temp2, challenge));
195                 if(!d0_bignum_cmp(temp4, one))
196                         break;
197                 if(++gcdfail == 3)
198                         return 0;
199                 ++gcdfail;
200         }
201         gcdfail = 0;
202         for (;;)
203         {
204                 CHECK(d0_bignum_rand_bit_exact(temp1, qb));
205                 if(!d0_bignum_cmp(temp1, temp0))
206                 {
207                         if(++fail == 3)
208                                 return 0;
209                 }
210                 fail = 0;
211                 if(d0_bignum_isprime(temp1, 10) == 0)
212                         continue;
213                 CHECK(d0_bignum_sub(temp3, temp1, one));
214                 CHECK(d0_bignum_gcd(temp4, NULL, NULL, temp3, challenge));
215                 if(!d0_bignum_cmp(temp4, one))
216                         break;
217                 if(++gcdfail == 3)
218                         return 0;
219                 ++gcdfail;
220         }
221
222         // n = temp0*temp1
223         CHECK(d0_bignum_mul(n, temp0, temp1));
224
225         // d = challenge^-1 mod (temp0-1)(temp1-1)
226         CHECK(d0_bignum_mul(temp0, temp2, temp3));
227         CHECK(d0_bignum_mod_inv(d, challenge, temp0));
228         return 1;
229 fail:
230         return 0;
231 }
232
233 D0_BOOL d0_rsa_generate_key_fastreject(size_t size, d0_fastreject_function reject, d0_blind_id_t *ctx, void *pass)
234 {
235         // uses temp0 to temp4
236         int fail = 0;
237         int gcdfail = 0;
238         int pb = (size + 1)/2;
239         int qb = size - pb;
240         if(pb < 8)
241                 pb = 8;
242         if(qb < 8)
243                 qb = 8;
244         for (;;)
245         {
246                 CHECK(d0_bignum_rand_bit_exact(temp0, pb));
247                 if(d0_bignum_isprime(temp0, 10) == 0)
248                         continue;
249                 CHECK(d0_bignum_sub(temp2, temp0, one));
250                 CHECK(d0_bignum_gcd(temp4, NULL, NULL, temp2, ctx->rsa_e));
251                 if(!d0_bignum_cmp(temp4, one))
252                         break;
253                 if(++gcdfail == 3)
254                         return 0;
255                 ++gcdfail;
256         }
257         gcdfail = 0;
258         for (;;)
259         {
260                 CHECK(d0_bignum_rand_bit_exact(temp1, qb));
261                 if(!d0_bignum_cmp(temp1, temp0))
262                 {
263                         if(++fail == 3)
264                                 return 0;
265                 }
266                 fail = 0;
267
268                 // n = temp0*temp1
269                 CHECK(d0_bignum_mul(ctx->rsa_n, temp0, temp1));
270                 if(reject(ctx, pass))
271                         continue;
272
273                 if(d0_bignum_isprime(temp1, 10) == 0)
274                         continue;
275                 CHECK(d0_bignum_sub(temp3, temp1, one));
276                 CHECK(d0_bignum_gcd(temp4, NULL, NULL, temp3, ctx->rsa_e));
277                 if(!d0_bignum_cmp(temp4, one))
278                         break;
279                 if(++gcdfail == 3)
280                         return 0;
281                 ++gcdfail;
282         }
283
284         // ctx->rsa_d = ctx->rsa_e^-1 mod (temp0-1)(temp1-1)
285         CHECK(d0_bignum_mul(temp0, temp2, temp3));
286         CHECK(d0_bignum_mod_inv(ctx->rsa_d, ctx->rsa_e, temp0));
287         return 1;
288 fail:
289         return 0;
290 }
291
292 D0_WARN_UNUSED_RESULT D0_BOOL d0_longhash_destructive(unsigned char *convbuf, size_t sz, unsigned char *outbuf, size_t outbuflen)
293 {
294         size_t n, i;
295
296         n = outbuflen;
297         while(n > SHA_DIGESTSIZE)
298         {
299                 memcpy(outbuf, sha(convbuf, sz), SHA_DIGESTSIZE);
300                 outbuf += SHA_DIGESTSIZE;
301                 n -= SHA_DIGESTSIZE;
302                 for(i = 0; i < sz; ++i)
303                         if(++convbuf[i])
304                                 break; // stop until no carry
305         }
306         memcpy(outbuf, sha(convbuf, sz), n);
307         return 1;
308 }
309
310 D0_WARN_UNUSED_RESULT D0_BOOL d0_longhash_bignum(const d0_bignum_t *in, unsigned char *outbuf, size_t outbuflen)
311 {
312         static unsigned char convbuf[1024];
313         size_t sz;
314
315         CHECK(d0_bignum_export_unsigned(in, convbuf, sizeof(convbuf)) >= 0);
316         sz = (d0_bignum_size(in) + 7) / 8;
317         CHECK(d0_longhash_destructive(convbuf, sz, outbuf, outbuflen));
318         return 1;
319
320 fail:
321         return 0;
322 }
323
324 void d0_blind_id_clear(d0_blind_id_t *ctx)
325 {
326         if(ctx->rsa_n) d0_bignum_free(ctx->rsa_n);
327         if(ctx->rsa_e) d0_bignum_free(ctx->rsa_e);
328         if(ctx->rsa_d) d0_bignum_free(ctx->rsa_d);
329         if(ctx->schnorr_G) d0_bignum_free(ctx->schnorr_G);
330         if(ctx->schnorr_s) d0_bignum_free(ctx->schnorr_s);
331         if(ctx->schnorr_g_to_s) d0_bignum_free(ctx->schnorr_g_to_s);
332         if(ctx->schnorr_H_g_to_s_signature) d0_bignum_free(ctx->schnorr_H_g_to_s_signature);
333         if(ctx->rsa_blind_signature_camouflage) d0_bignum_free(ctx->rsa_blind_signature_camouflage);
334         if(ctx->r) d0_bignum_free(ctx->r);
335         if(ctx->challenge) d0_bignum_free(ctx->challenge);
336         if(ctx->t) d0_bignum_free(ctx->t);
337         if(ctx->g_to_t) d0_bignum_free(ctx->g_to_t);
338         if(ctx->other_g_to_t) d0_bignum_free(ctx->other_g_to_t);
339         memset(ctx, 0, sizeof(*ctx));
340 }
341
342 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_copy(d0_blind_id_t *ctx, const d0_blind_id_t *src)
343 {
344         d0_blind_id_clear(ctx);
345         if(src->rsa_n) CHECK_ASSIGN(ctx->rsa_n, d0_bignum_mov(NULL, src->rsa_n));
346         if(src->rsa_e) CHECK_ASSIGN(ctx->rsa_e, d0_bignum_mov(NULL, src->rsa_e));
347         if(src->rsa_d) CHECK_ASSIGN(ctx->rsa_d, d0_bignum_mov(NULL, src->rsa_d));
348         if(src->schnorr_G) CHECK_ASSIGN(ctx->schnorr_G, d0_bignum_mov(NULL, src->schnorr_G));
349         if(src->schnorr_s) CHECK_ASSIGN(ctx->schnorr_s, d0_bignum_mov(NULL, src->schnorr_s));
350         if(src->schnorr_g_to_s) CHECK_ASSIGN(ctx->schnorr_g_to_s, d0_bignum_mov(NULL, src->schnorr_g_to_s));
351         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));
352         if(src->rsa_blind_signature_camouflage) CHECK_ASSIGN(ctx->rsa_blind_signature_camouflage, d0_bignum_mov(NULL, src->rsa_blind_signature_camouflage));
353         if(src->r) CHECK_ASSIGN(ctx->r, d0_bignum_mov(NULL, src->r));
354         if(src->challenge) CHECK_ASSIGN(ctx->challenge, d0_bignum_mov(NULL, src->challenge));
355         if(src->t) CHECK_ASSIGN(ctx->t, d0_bignum_mov(NULL, src->t));
356         if(src->g_to_t) CHECK_ASSIGN(ctx->g_to_t, d0_bignum_mov(NULL, src->g_to_t));
357         if(src->other_g_to_t) CHECK_ASSIGN(ctx->other_g_to_t, d0_bignum_mov(NULL, src->other_g_to_t));
358         memcpy(ctx->msg, src->msg, sizeof(ctx->msg));
359         ctx->msglen = src->msglen;
360         memcpy(ctx->msghash, src->msghash, sizeof(ctx->msghash));
361         return 1;
362 fail:
363         d0_blind_id_clear(ctx);
364         return 0;
365 }
366
367 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)
368 {
369         REPLACING(rsa_e); REPLACING(rsa_d); REPLACING(rsa_n);
370
371         CHECK_ASSIGN(ctx->rsa_e, d0_bignum_int(ctx->rsa_e, 65537));
372         CHECK_ASSIGN(ctx->rsa_d, d0_bignum_zero(ctx->rsa_d));
373         CHECK_ASSIGN(ctx->rsa_n, d0_bignum_zero(ctx->rsa_n));
374         if(reject)
375                 CHECK(d0_rsa_generate_key_fastreject(k+1, reject, ctx, pass)); // must fit G for sure
376         else
377                 CHECK(d0_rsa_generate_key(k+1, ctx->rsa_e, ctx->rsa_d, ctx->rsa_n)); // must fit G for sure
378         return 1;
379 fail:
380         return 0;
381 }
382
383 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_generate_private_key(d0_blind_id_t *ctx, int k)
384 {
385         return d0_blind_id_generate_private_key_fastreject(ctx, k, NULL, NULL);
386 }
387
388 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_read_private_key(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
389 {
390         d0_iobuf_t *in = NULL;
391
392         REPLACING(rsa_n); REPLACING(rsa_e); REPLACING(rsa_d);
393
394         in = d0_iobuf_open_read(inbuf, inbuflen);
395
396         CHECK_ASSIGN(ctx->rsa_n, d0_iobuf_read_bignum(in, ctx->rsa_n));
397         CHECK_ASSIGN(ctx->rsa_e, d0_iobuf_read_bignum(in, ctx->rsa_e));
398         CHECK_ASSIGN(ctx->rsa_d, d0_iobuf_read_bignum(in, ctx->rsa_d));
399         return d0_iobuf_close(in, NULL);
400
401 fail:
402         d0_iobuf_close(in, NULL);
403         return 0;
404 }
405
406 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_read_public_key(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
407 {
408         d0_iobuf_t *in = NULL;
409
410         REPLACING(rsa_n); REPLACING(rsa_e);
411
412         in = d0_iobuf_open_read(inbuf, inbuflen);
413         CHECK_ASSIGN(ctx->rsa_n, d0_iobuf_read_bignum(in, ctx->rsa_n));
414         CHECK_ASSIGN(ctx->rsa_e, d0_iobuf_read_bignum(in, ctx->rsa_e));
415         return d0_iobuf_close(in, NULL);
416
417 fail:
418         d0_iobuf_close(in, NULL);
419         return 0;
420 }
421
422 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_write_private_key(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
423 {
424         d0_iobuf_t *out = NULL;
425
426         USING(rsa_n); USING(rsa_e); USING(rsa_d);
427
428         out = d0_iobuf_open_write(outbuf, *outbuflen);
429         CHECK(d0_iobuf_write_bignum(out, ctx->rsa_n));
430         CHECK(d0_iobuf_write_bignum(out, ctx->rsa_e));
431         CHECK(d0_iobuf_write_bignum(out, ctx->rsa_d));
432         return d0_iobuf_close(out, outbuflen);
433
434 fail:
435         d0_iobuf_close(out, outbuflen);
436         return 0;
437 }
438
439 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_write_public_key(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
440 {
441         d0_iobuf_t *out = NULL;
442
443         USING(rsa_n); USING(rsa_e);
444
445         out = d0_iobuf_open_write(outbuf, *outbuflen);
446         CHECK(d0_iobuf_write_bignum(out, ctx->rsa_n));
447         CHECK(d0_iobuf_write_bignum(out, ctx->rsa_e));
448         return d0_iobuf_close(out, outbuflen);
449
450 fail:
451         if(!d0_iobuf_close(out, outbuflen))
452                 return 0;
453         return 0;
454 }
455
456 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_fingerprint64_public_key(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
457 {
458         d0_iobuf_t *out = NULL;
459         static unsigned char convbuf[2048];
460         d0_iobuf_t *conv = NULL;
461         size_t sz, n;
462
463         USING(rsa_n); USING(rsa_e);
464
465         out = d0_iobuf_open_write(outbuf, *outbuflen);
466         conv = d0_iobuf_open_write(convbuf, sizeof(convbuf));
467
468         CHECK(d0_iobuf_write_bignum(conv, ctx->rsa_n));
469         CHECK(d0_iobuf_write_bignum(conv, ctx->rsa_e));
470         CHECK(d0_iobuf_close(conv, &sz));
471         conv = NULL;
472
473         n = (*outbuflen / 4) * 3;
474         if(n > SHA_DIGESTSIZE)
475                 n = SHA_DIGESTSIZE;
476         CHECK(d0_iobuf_write_raw(out, sha(convbuf, sz), n) == n);
477         CHECK(d0_iobuf_conv_base64_out(out));
478
479         return d0_iobuf_close(out, outbuflen);
480
481 fail:
482         if(conv)
483                 d0_iobuf_close(conv, &sz);
484         d0_iobuf_close(out, outbuflen);
485         return 0;
486 }
487
488 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_generate_private_id_modulus(d0_blind_id_t *ctx)
489 {
490         USING(rsa_n);
491         REPLACING(schnorr_G);
492
493         CHECK_ASSIGN(ctx->schnorr_G, d0_bignum_zero(ctx->schnorr_G));
494         CHECK(d0_dl_generate_key(d0_bignum_size(ctx->rsa_n)-1, ctx->schnorr_G));
495         return 1;
496 fail:
497         return 0;
498 }
499
500 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_read_private_id_modulus(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
501 {
502         d0_iobuf_t *in = NULL;
503
504         REPLACING(schnorr_G);
505
506         in = d0_iobuf_open_read(inbuf, inbuflen);
507         CHECK_ASSIGN(ctx->schnorr_G, d0_iobuf_read_bignum(in, ctx->schnorr_G));
508         return d0_iobuf_close(in, NULL);
509
510 fail:
511         d0_iobuf_close(in, NULL);
512         return 0;
513 }
514
515 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_write_private_id_modulus(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
516 {
517         d0_iobuf_t *out = NULL;
518
519         USING(schnorr_G);
520
521         out = d0_iobuf_open_write(outbuf, *outbuflen);
522         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_G));
523         return d0_iobuf_close(out, outbuflen);
524
525 fail:
526         d0_iobuf_close(out, outbuflen);
527         return 0;
528 }
529
530 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_generate_private_id_start(d0_blind_id_t *ctx)
531 {
532         // temps: temp0 = order
533         USING(schnorr_G);
534         REPLACING(schnorr_s); REPLACING(schnorr_g_to_s);
535
536         CHECK(d0_dl_get_order(temp0, ctx->schnorr_G));
537         CHECK_ASSIGN(ctx->schnorr_s, d0_bignum_rand_range(ctx->schnorr_s, zero, temp0));
538         CHECK_ASSIGN(ctx->schnorr_g_to_s, d0_bignum_mod_pow(ctx->schnorr_g_to_s, four, ctx->schnorr_s, ctx->schnorr_G));
539         CHECK_ASSIGN(ctx->schnorr_H_g_to_s_signature, d0_bignum_zero(ctx->schnorr_H_g_to_s_signature));
540         return 1;
541
542 fail:
543         return 0;
544 }
545
546 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_generate_private_id_request(d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
547 {
548         d0_iobuf_t *out = NULL;
549         static unsigned char shabuf[2048];
550         size_t sz;
551
552         // temps: temp0 rsa_blind_signature_camouflage^challenge, temp1 (4^s)*rsa_blind_signature_camouflage^challenge
553         USING(rsa_n); USING(rsa_e); USING(schnorr_g_to_s);
554         REPLACING(rsa_blind_signature_camouflage);
555
556         out = d0_iobuf_open_write(outbuf, *outbuflen);
557
558         CHECK_ASSIGN(ctx->rsa_blind_signature_camouflage, d0_bignum_rand_bit_atmost(ctx->rsa_blind_signature_camouflage, d0_bignum_size(ctx->rsa_n)));
559         CHECK(d0_bignum_mod_pow(temp0, ctx->rsa_blind_signature_camouflage, ctx->rsa_e, ctx->rsa_n));
560
561         // we will actually sign HA(4^s) to prevent a malleability attack!
562         CHECK(d0_bignum_mov(temp2, ctx->schnorr_g_to_s));
563         sz = (d0_bignum_size(ctx->rsa_n) + 7) / 8; // this is too long, so we have to take the value % rsa_n when "decrypting"
564         if(sz > sizeof(shabuf))
565                 sz = sizeof(shabuf);
566         CHECK(d0_longhash_bignum(temp2, shabuf, sz));
567         CHECK(d0_bignum_import_unsigned(temp2, shabuf, sz));
568
569         // hash complete
570         CHECK(d0_bignum_mod_mul(temp1, temp2, temp0, ctx->rsa_n));
571         CHECK(d0_iobuf_write_bignum(out, temp1));
572         return d0_iobuf_close(out, outbuflen);
573
574 fail:
575         d0_iobuf_close(out, outbuflen);
576         return 0;
577 }
578
579 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)
580 {
581         d0_iobuf_t *in = NULL;
582         d0_iobuf_t *out = NULL;
583
584         // temps: temp0 input, temp1 temp0^d
585         USING(rsa_d); USING(rsa_n);
586
587         in = d0_iobuf_open_read(inbuf, inbuflen);
588         out = d0_iobuf_open_write(outbuf, *outbuflen);
589
590         CHECK(d0_iobuf_read_bignum(in, temp0));
591         CHECK(d0_bignum_mod_pow(temp1, temp0, ctx->rsa_d, ctx->rsa_n));
592         CHECK(d0_iobuf_write_bignum(out, temp1));
593
594         d0_iobuf_close(in, NULL);
595         return d0_iobuf_close(out, outbuflen);
596
597 fail:
598         d0_iobuf_close(in, NULL);
599         d0_iobuf_close(out, outbuflen);
600         return 0;
601 }
602
603 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_finish_private_id_request(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
604 {
605         d0_iobuf_t *in = NULL;
606
607         // temps: temp0 input, temp1 rsa_blind_signature_camouflage^-1
608         USING(rsa_blind_signature_camouflage); USING(rsa_n);
609         REPLACING(schnorr_H_g_to_s_signature);
610
611         in = d0_iobuf_open_read(inbuf, inbuflen);
612
613         CHECK(d0_iobuf_read_bignum(in, temp0));
614         CHECK(d0_bignum_mod_inv(temp1, ctx->rsa_blind_signature_camouflage, ctx->rsa_n));
615         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));
616
617         return d0_iobuf_close(in, NULL);
618
619 fail:
620         d0_iobuf_close(in, NULL);
621         return 0;
622 }
623
624 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)
625 {
626         d0_iobuf_t *in = NULL;
627
628         REPLACING(rsa_blind_signature_camouflage);
629
630         in = d0_iobuf_open_read(inbuf, inbuflen);
631
632         CHECK_ASSIGN(ctx->rsa_blind_signature_camouflage, d0_iobuf_read_bignum(in, ctx->rsa_blind_signature_camouflage));
633
634         return d0_iobuf_close(in, NULL);
635
636 fail:
637         d0_iobuf_close(in, NULL);
638         return 0;
639 }
640
641 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)
642 {
643         d0_iobuf_t *out = NULL;
644
645         USING(rsa_blind_signature_camouflage);
646
647         out = d0_iobuf_open_write(outbuf, *outbuflen);
648
649         CHECK(d0_iobuf_write_bignum(out, ctx->rsa_blind_signature_camouflage));
650
651         return d0_iobuf_close(out, outbuflen);
652
653 fail:
654         d0_iobuf_close(out, outbuflen);
655         return 0;
656 }
657
658 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_read_private_id(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
659 {
660         d0_iobuf_t *in = NULL;
661
662         REPLACING(schnorr_s); REPLACING(schnorr_g_to_s); REPLACING(schnorr_H_g_to_s_signature);
663
664         in = d0_iobuf_open_read(inbuf, inbuflen);
665
666         CHECK_ASSIGN(ctx->schnorr_s, d0_iobuf_read_bignum(in, ctx->schnorr_s));
667         CHECK_ASSIGN(ctx->schnorr_g_to_s, d0_iobuf_read_bignum(in, ctx->schnorr_g_to_s));
668         CHECK_ASSIGN(ctx->schnorr_H_g_to_s_signature, d0_iobuf_read_bignum(in, ctx->schnorr_H_g_to_s_signature));
669
670         return d0_iobuf_close(in, NULL);
671
672 fail:
673         d0_iobuf_close(in, NULL);
674         return 0;
675 }
676
677 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_read_public_id(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
678 {
679         d0_iobuf_t *in = NULL;
680
681         REPLACING(schnorr_g_to_s); REPLACING(schnorr_H_g_to_s_signature);
682
683         in = d0_iobuf_open_read(inbuf, inbuflen);
684
685         CHECK_ASSIGN(ctx->schnorr_g_to_s, d0_iobuf_read_bignum(in, ctx->schnorr_g_to_s));
686         CHECK_ASSIGN(ctx->schnorr_H_g_to_s_signature, d0_iobuf_read_bignum(in, ctx->schnorr_H_g_to_s_signature));
687
688         return d0_iobuf_close(in, NULL);
689
690 fail:
691         d0_iobuf_close(in, NULL);
692         return 0;
693 }
694
695 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_write_private_id(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
696 {
697         d0_iobuf_t *out = NULL;
698
699         USING(schnorr_s); USING(schnorr_g_to_s); USING(schnorr_H_g_to_s_signature);
700
701         out = d0_iobuf_open_write(outbuf, *outbuflen);
702
703         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_s));
704         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_g_to_s));
705         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_H_g_to_s_signature));
706
707         return d0_iobuf_close(out, outbuflen);
708
709 fail:
710         d0_iobuf_close(out, outbuflen);
711         return 0;
712 }
713
714 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_write_public_id(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
715 {
716         d0_iobuf_t *out = NULL;
717
718         USING(schnorr_g_to_s); USING(schnorr_H_g_to_s_signature);
719
720         out = d0_iobuf_open_write(outbuf, *outbuflen);
721
722         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_g_to_s));
723         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_H_g_to_s_signature));
724
725         return d0_iobuf_close(out, outbuflen);
726
727 fail:
728         d0_iobuf_close(out, outbuflen);
729         return 0;
730 }
731
732 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)
733 // start =
734 //   first run: send 4^s, 4^s signature
735 //   1. get random r, send HASH(4^r)
736 {
737         d0_iobuf_t *out = NULL;
738         static unsigned char convbuf[1024];
739         d0_iobuf_t *conv = NULL;
740         size_t sz = 0;
741         D0_BOOL failed = 0;
742
743         // temps: temp0 order, temp0 4^r
744         if(is_first)
745         {
746                 USING(schnorr_g_to_s); USING(schnorr_H_g_to_s_signature);
747         }
748         USING(schnorr_G);
749         REPLACING(r); REPLACING(t); REPLACING(g_to_t);
750
751         out = d0_iobuf_open_write(outbuf, *outbuflen);
752
753         if(is_first)
754         {
755                 // send ID
756                 if(send_modulus)
757                         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_G));
758                 CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_g_to_s));
759                 CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_H_g_to_s_signature));
760         }
761
762         // start schnorr ID scheme
763         // generate random number r; x = g^r; send hash of x, remember r, forget x
764         CHECK(d0_dl_get_order(temp0, ctx->schnorr_G));
765         CHECK_ASSIGN(ctx->r, d0_bignum_rand_range(ctx->r, zero, temp0));
766         //CHECK(d0_bignum_mod_pow(temp0, four, ctx->r, ctx->schnorr_G));
767
768         // initialize Signed Diffie Hellmann
769         // we already have the group order in temp1
770         CHECK_ASSIGN(ctx->t, d0_bignum_rand_range(ctx->t, zero, temp0));
771         // can we SOMEHOW do this with just one mod_pow?
772
773         CHECK(d0_bignum_mod_pow(temp0, four, ctx->r, ctx->schnorr_G));
774         CHECK_ASSIGN(ctx->g_to_t, d0_bignum_mod_pow(ctx->g_to_t, four, ctx->t, ctx->schnorr_G));
775         CHECK(!failed);
776
777         // hash it, hash it, everybody hash it
778         conv = d0_iobuf_open_write(convbuf, sizeof(convbuf));
779         CHECK(d0_iobuf_write_bignum(conv, temp0));
780         CHECK(d0_iobuf_write_bignum(conv, ctx->g_to_t));
781         CHECK(d0_iobuf_write_packet(conv, msg, msglen));
782         CHECK(d0_iobuf_write_bignum(conv, temp0));
783         CHECK(d0_iobuf_write_bignum(conv, ctx->g_to_t));
784         d0_iobuf_close(conv, &sz);
785         conv = NULL;
786         CHECK(d0_iobuf_write_raw(out, sha(convbuf, sz), SCHNORR_HASHSIZE) == SCHNORR_HASHSIZE);
787         CHECK(d0_iobuf_write_packet(out, msg, msglen));
788
789         return d0_iobuf_close(out, outbuflen);
790
791 fail:
792         d0_iobuf_close(out, outbuflen);
793         return 0;
794 }
795
796 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)
797 //   first run: get 4^s, 4^s signature
798 //   1. check sig
799 //   2. save HASH(4^r)
800 //   3. send challenge challenge of SCHNORR_BITS
801 {
802         d0_iobuf_t *in = NULL;
803         d0_iobuf_t *out = NULL;
804         static unsigned char shabuf[2048];
805         size_t sz;
806
807         // temps: temp0 order, temp0 signature check
808         if(is_first)
809         {
810                 REPLACING(schnorr_g_to_s); REPLACING(schnorr_H_g_to_s_signature);
811                 if(recv_modulus)
812                         REPLACING(schnorr_G);
813                 else
814                         USING(schnorr_G);
815         }
816         else
817         {
818                 USING(schnorr_g_to_s); USING(schnorr_H_g_to_s_signature);
819                 USING(schnorr_G);
820         }
821         USING(rsa_e); USING(rsa_n);
822         REPLACING(challenge); REPLACING(msg); REPLACING(msglen); REPLACING(msghash); REPLACING(r); REPLACING(t);
823
824         in = d0_iobuf_open_read(inbuf, inbuflen);
825         out = d0_iobuf_open_write(outbuf, *outbuflen);
826
827         if(is_first)
828         {
829                 if(recv_modulus)
830                 {
831                         CHECK_ASSIGN(ctx->schnorr_G, d0_iobuf_read_bignum(in, ctx->schnorr_G));
832                         CHECK(d0_bignum_cmp(ctx->schnorr_G, zero) > 0);
833                         CHECK(d0_bignum_cmp(ctx->schnorr_G, ctx->rsa_n) < 0);
834                 }
835                 CHECK_ASSIGN(ctx->schnorr_g_to_s, d0_iobuf_read_bignum(in, ctx->schnorr_g_to_s));
836                 CHECK(d0_bignum_cmp(ctx->schnorr_g_to_s, zero) >= 0);
837                 CHECK(d0_bignum_cmp(ctx->schnorr_g_to_s, ctx->schnorr_G) < 0);
838                 CHECK_ASSIGN(ctx->schnorr_H_g_to_s_signature, d0_iobuf_read_bignum(in, ctx->schnorr_H_g_to_s_signature));
839                 CHECK(d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, zero) >= 0);
840                 CHECK(d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, ctx->rsa_n) < 0);
841
842                 // check signature of key (t = k^d, so, t^challenge = k)
843                 CHECK(d0_bignum_mod_pow(temp0, ctx->schnorr_H_g_to_s_signature, ctx->rsa_e, ctx->rsa_n));
844
845                 // we will actually sign SHA(4^s) to prevent a malleability attack!
846                 CHECK(d0_bignum_mov(temp2, ctx->schnorr_g_to_s));
847                 sz = (d0_bignum_size(ctx->rsa_n) + 7) / 8; // this is too long, so we have to take the value % rsa_n when "decrypting"
848                 if(sz > sizeof(shabuf))
849                         sz = sizeof(shabuf);
850                 CHECK(d0_longhash_bignum(temp2, shabuf, sz));
851                 CHECK(d0_bignum_import_unsigned(temp2, shabuf, sz));
852
853                 // + 7 / 8 is too large, so let's mod it
854                 CHECK(d0_bignum_divmod(NULL, temp1, temp2, ctx->rsa_n));
855
856                 // hash complete
857                 if(d0_bignum_cmp(temp0, temp1))
858                 {
859                         // accept the key anyway, but mark as failed signature! will later return 0 in status
860                         CHECK(d0_bignum_zero(ctx->schnorr_H_g_to_s_signature));
861                 }
862         }
863
864         CHECK(d0_iobuf_read_raw(in, ctx->msghash, SCHNORR_HASHSIZE));
865         ctx->msglen = MSGSIZE;
866         CHECK(d0_iobuf_read_packet(in, ctx->msg, &ctx->msglen));
867
868         // send challenge
869         CHECK_ASSIGN(ctx->challenge, d0_bignum_rand_bit_atmost(ctx->challenge, SCHNORR_BITS));
870         CHECK(d0_iobuf_write_bignum(out, ctx->challenge));
871
872         // Diffie Hellmann send
873         CHECK(d0_dl_get_order(temp0, ctx->schnorr_G));
874         CHECK_ASSIGN(ctx->t, d0_bignum_rand_range(ctx->t, zero, temp0));
875         CHECK(d0_bignum_mod_pow(temp0, four, ctx->t, ctx->schnorr_G));
876         CHECK(d0_iobuf_write_bignum(out, temp0));
877
878         if(status)
879                 *status = !!d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, zero);
880
881         d0_iobuf_close(in, NULL);
882         return d0_iobuf_close(out, outbuflen);
883
884 fail:
885         d0_iobuf_close(in, NULL);
886         d0_iobuf_close(out, outbuflen);
887         return 0;
888 }
889
890 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)
891 //   1. read challenge challenge of SCHNORR_BITS
892 //   2. reply with r + s * challenge mod order
893 {
894         d0_iobuf_t *in = NULL;
895         d0_iobuf_t *out = NULL;
896
897         // temps: 0 order, 1 prod, 2 y, 3 challenge
898         REPLACING(other_g_to_t); REPLACING(t);
899         USING(schnorr_G); USING(schnorr_s); USING(r); USING(g_to_t);
900
901         in = d0_iobuf_open_read(inbuf, inbuflen);
902         out = d0_iobuf_open_write(outbuf, *outbuflen);
903
904         CHECK(d0_iobuf_read_bignum(in, temp3));
905         CHECK(d0_bignum_cmp(temp3, zero) >= 0);
906         CHECK(d0_bignum_size(temp3) <= SCHNORR_BITS);
907
908         // send response for schnorr ID scheme
909         // i.challenge. r + ctx->schnorr_s * temp3
910         CHECK(d0_dl_get_order(temp0, ctx->schnorr_G));
911         CHECK(d0_bignum_mod_mul(temp1, ctx->schnorr_s, temp3, temp0));
912         CHECK(d0_bignum_mod_add(temp2, temp1, ctx->r, temp0));
913         CHECK(d0_iobuf_write_bignum(out, temp2));
914
915         // Diffie Hellmann recv
916         CHECK_ASSIGN(ctx->other_g_to_t, d0_iobuf_read_bignum(in, ctx->other_g_to_t));
917         CHECK(d0_bignum_cmp(ctx->other_g_to_t, zero) > 0);
918         CHECK(d0_bignum_cmp(ctx->other_g_to_t, ctx->schnorr_G) < 0);
919         // Diffie Hellmann send
920         CHECK(d0_iobuf_write_bignum(out, ctx->g_to_t));
921
922         d0_iobuf_close(in, NULL);
923         return d0_iobuf_close(out, outbuflen);
924
925 fail:
926         d0_iobuf_close(in, NULL);
927         d0_iobuf_close(out, outbuflen);
928         return 0;
929 }
930
931 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)
932 //   1. read y = r + s * challenge mod order
933 //   2. verify: g^y (g^s)^-challenge = g^(r+s*challenge-s*challenge) = g^r
934 //      (check using H(g^r) which we know)
935 {
936         d0_iobuf_t *in = NULL;
937         static unsigned char convbuf[1024];
938         d0_iobuf_t *conv = NULL;
939         size_t sz;
940
941         // temps: 0 y 1 order
942         USING(challenge); USING(schnorr_G);
943         REPLACING(other_g_to_t);
944
945         in = d0_iobuf_open_read(inbuf, inbuflen);
946
947         CHECK(d0_dl_get_order(temp1, ctx->schnorr_G));
948         CHECK(d0_iobuf_read_bignum(in, temp0));
949         CHECK(d0_bignum_cmp(temp0, zero) >= 0);
950         CHECK(d0_bignum_cmp(temp0, temp1) < 0);
951
952         // verify schnorr ID scheme
953         // we need 4^r = 4^temp0 (g^s)^-challenge
954         CHECK(d0_bignum_mod_inv(temp1, ctx->schnorr_g_to_s, ctx->schnorr_G));
955         CHECK(d0_bignum_mod_pow(temp2, temp1, ctx->challenge, ctx->schnorr_G));
956         CHECK(d0_bignum_mod_pow(temp1, four, temp0, ctx->schnorr_G));
957         CHECK_ASSIGN(temp3, d0_bignum_mod_mul(temp3, temp1, temp2, ctx->schnorr_G));
958
959         // Diffie Hellmann recv
960         CHECK_ASSIGN(ctx->other_g_to_t, d0_iobuf_read_bignum(in, ctx->other_g_to_t));
961         CHECK(d0_bignum_cmp(ctx->other_g_to_t, zero) > 0);
962         CHECK(d0_bignum_cmp(ctx->other_g_to_t, ctx->schnorr_G) < 0);
963
964         // hash it, hash it, everybody hash it
965         conv = d0_iobuf_open_write(convbuf, sizeof(convbuf));
966         CHECK(d0_iobuf_write_bignum(conv, temp3));
967         CHECK(d0_iobuf_write_bignum(conv, ctx->other_g_to_t));
968         CHECK(d0_iobuf_write_packet(conv, ctx->msg, ctx->msglen));
969         CHECK(d0_iobuf_write_bignum(conv, temp3));
970         CHECK(d0_iobuf_write_bignum(conv, ctx->other_g_to_t));
971         d0_iobuf_close(conv, &sz);
972         conv = NULL;
973         if(memcmp(sha(convbuf, sz), ctx->msghash, SCHNORR_HASHSIZE))
974         {
975                 // FAIL (not owned by player)
976                 goto fail;
977         }
978
979         if(status)
980                 *status = !!d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, zero);
981
982         if(ctx->msglen <= *msglen)
983                 memcpy(msg, ctx->msg, ctx->msglen);
984         else
985                 memcpy(msg, ctx->msg, *msglen);
986         *msglen = ctx->msglen;
987
988         d0_iobuf_close(in, NULL);
989         return 1;
990
991 fail:
992         d0_iobuf_close(in, NULL);
993         return 0;
994 }
995
996 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_authenticate_with_private_id_generate_missing_signature(d0_blind_id_t *ctx)
997 {
998         size_t sz;
999         static unsigned char shabuf[2048];
1000
1001         REPLACING(schnorr_H_g_to_s_signature);
1002         USING(schnorr_g_to_s); USING(rsa_d); USING(rsa_n);
1003
1004         // we will actually sign SHA(4^s) to prevent a malleability attack!
1005         CHECK(d0_bignum_mov(temp2, ctx->schnorr_g_to_s));
1006         sz = (d0_bignum_size(ctx->rsa_n) + 7) / 8; // this is too long, so we have to take the value % rsa_n when "decrypting"
1007         if(sz > sizeof(shabuf))
1008                 sz = sizeof(shabuf);
1009         CHECK(d0_longhash_bignum(temp2, shabuf, sz));
1010         CHECK(d0_bignum_import_unsigned(temp2, shabuf, sz));
1011
1012         // + 7 / 8 is too large, so let's mod it
1013         CHECK(d0_bignum_divmod(NULL, temp1, temp2, ctx->rsa_n));
1014         CHECK(d0_bignum_mod_pow(ctx->schnorr_H_g_to_s_signature, temp1, ctx->rsa_d, ctx->rsa_n));
1015         return 1;
1016
1017 fail:
1018         return 0;
1019 }
1020
1021 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)
1022 {
1023         d0_iobuf_t *out = NULL;
1024         static unsigned char convbuf[1024];
1025         static unsigned char shabuf[1024];
1026         d0_iobuf_t *conv = NULL;
1027         size_t sz = 0;
1028
1029         if(is_first)
1030         {
1031                 USING(schnorr_g_to_s); USING(schnorr_H_g_to_s_signature);
1032         }
1033         USING(schnorr_G);
1034         USING(schnorr_s);
1035         REPLACING(r);
1036
1037         out = d0_iobuf_open_write(outbuf, *outbuflen);
1038
1039         if(is_first)
1040         {
1041                 // send ID
1042                 if(send_modulus)
1043                         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_G));
1044                 CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_g_to_s));
1045                 CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_H_g_to_s_signature));
1046         }
1047
1048         // start schnorr SIGNATURE scheme
1049         // generate random number r; x = g^r; send hash of H(m||r), remember r, forget x
1050         CHECK(d0_dl_get_order(temp0, ctx->schnorr_G));
1051         CHECK_ASSIGN(ctx->r, d0_bignum_rand_range(ctx->r, zero, temp0));
1052         CHECK(d0_bignum_mod_pow(temp1, four, ctx->r, ctx->schnorr_G));
1053
1054         // hash it, hash it, everybody hash it
1055         conv = d0_iobuf_open_write(convbuf, sizeof(convbuf));
1056         CHECK(d0_iobuf_write_packet(conv, message, msglen));
1057         CHECK(d0_iobuf_write_bignum(conv, temp1));
1058         d0_iobuf_close(conv, &sz);
1059         conv = NULL;
1060         CHECK(d0_longhash_destructive(convbuf, sz, shabuf, (d0_bignum_size(temp0) + 7) / 8));
1061         CHECK(d0_bignum_import_unsigned(temp2, shabuf, (d0_bignum_size(temp0) + 7) / 8));
1062         CHECK(d0_iobuf_write_bignum(out, temp2));
1063
1064         // multiply with secret, sub k, modulo order
1065         CHECK(d0_bignum_mod_mul(temp1, temp2, ctx->schnorr_s, temp0));
1066         CHECK(d0_bignum_mod_sub(temp2, ctx->r, temp1, temp0));
1067         CHECK(d0_iobuf_write_bignum(out, temp2));
1068
1069         // write the message itself
1070         CHECK(d0_iobuf_write_packet(out, message, msglen));
1071
1072         return d0_iobuf_close(out, outbuflen);
1073
1074 fail:
1075         d0_iobuf_close(out, outbuflen);
1076         return 0;
1077 }
1078
1079 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)
1080 {
1081         d0_iobuf_t *in = NULL;
1082         d0_iobuf_t *conv = NULL;
1083         static unsigned char convbuf[2048];
1084         static unsigned char shabuf[2048];
1085         size_t sz;
1086
1087         if(is_first)
1088         {
1089                 REPLACING(schnorr_g_to_s); REPLACING(schnorr_H_g_to_s_signature);
1090                 if(recv_modulus)
1091                         REPLACING(schnorr_G);
1092                 else
1093                         USING(schnorr_G);
1094         }
1095         else
1096         {
1097                 USING(schnorr_g_to_s); USING(schnorr_H_g_to_s_signature);
1098                 USING(schnorr_G);
1099         }
1100         USING(rsa_e); USING(rsa_n);
1101
1102         in = d0_iobuf_open_read(inbuf, inbuflen);
1103
1104         if(is_first)
1105         {
1106                 if(recv_modulus)
1107                 {
1108                         CHECK_ASSIGN(ctx->schnorr_G, d0_iobuf_read_bignum(in, ctx->schnorr_G));
1109                         CHECK(d0_bignum_cmp(ctx->schnorr_G, zero) > 0);
1110                         CHECK(d0_bignum_cmp(ctx->schnorr_G, ctx->rsa_n) < 0);
1111                 }
1112                 CHECK_ASSIGN(ctx->schnorr_g_to_s, d0_iobuf_read_bignum(in, ctx->schnorr_g_to_s));
1113                 CHECK(d0_bignum_cmp(ctx->schnorr_g_to_s, zero) >= 0);
1114                 CHECK(d0_bignum_cmp(ctx->schnorr_g_to_s, ctx->schnorr_G) < 0);
1115                 CHECK_ASSIGN(ctx->schnorr_H_g_to_s_signature, d0_iobuf_read_bignum(in, ctx->schnorr_H_g_to_s_signature));
1116                 CHECK(d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, zero) >= 0);
1117                 CHECK(d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, ctx->rsa_n) < 0);
1118
1119                 // check signature of key (t = k^d, so, t^challenge = k)
1120                 CHECK(d0_bignum_mod_pow(temp0, ctx->schnorr_H_g_to_s_signature, ctx->rsa_e, ctx->rsa_n));
1121
1122                 // we will actually sign SHA(4^s) to prevent a malleability attack!
1123                 CHECK(d0_bignum_mov(temp2, ctx->schnorr_g_to_s));
1124                 sz = (d0_bignum_size(ctx->rsa_n) + 7) / 8; // this is too long, so we have to take the value % rsa_n when "decrypting"
1125                 if(sz > sizeof(shabuf))
1126                         sz = sizeof(shabuf);
1127                 CHECK(d0_longhash_bignum(temp2, shabuf, sz));
1128                 CHECK(d0_bignum_import_unsigned(temp2, shabuf, sz));
1129
1130                 // + 7 / 8 is too large, so let's mod it
1131                 CHECK(d0_bignum_divmod(NULL, temp1, temp2, ctx->rsa_n));
1132
1133                 // hash complete
1134                 if(d0_bignum_cmp(temp0, temp1))
1135                 {
1136                         // accept the key anyway, but mark as failed signature! will later return 0 in status
1137                         CHECK(d0_bignum_zero(ctx->schnorr_H_g_to_s_signature));
1138                 }
1139         }
1140
1141         CHECK(d0_dl_get_order(temp4, ctx->schnorr_G));
1142         CHECK(d0_iobuf_read_bignum(in, temp0)); // e == H(m || g^r)
1143         CHECK(d0_iobuf_read_bignum(in, temp1)); // x == (r - s*e) mod |G|
1144         CHECK(d0_iobuf_read_packet(in, msg, msglen));
1145
1146         // VERIFY: g^x * (g^s)^-e = g^(x - s*e) = g^r
1147
1148         // verify schnorr ID scheme
1149         // we need g^r = g^x (g^s)^e
1150         CHECK(d0_bignum_mod_pow(temp2, four, temp1, ctx->schnorr_G));
1151         CHECK(d0_bignum_mod_pow(temp1, ctx->schnorr_g_to_s, temp0, ctx->schnorr_G));
1152         CHECK_ASSIGN(temp3, d0_bignum_mod_mul(temp3, temp1, temp2, ctx->schnorr_G)); // temp3 now is g^r
1153
1154         // hash it, hash it, everybody hash it
1155         conv = d0_iobuf_open_write(convbuf, sizeof(convbuf));
1156         CHECK(d0_iobuf_write_packet(conv, msg, *msglen));
1157         CHECK(d0_iobuf_write_bignum(conv, temp3));
1158         d0_iobuf_close(conv, &sz);
1159         conv = NULL;
1160         CHECK(d0_longhash_destructive(convbuf, sz, shabuf, (d0_bignum_size(temp4) + 7) / 8));
1161         CHECK(d0_bignum_import_unsigned(temp1, shabuf, (d0_bignum_size(temp4) + 7) / 8));
1162
1163         // verify signature
1164         CHECK(!d0_bignum_cmp(temp0, temp1));
1165
1166         if(status)
1167                 *status = !!d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, zero);
1168
1169         d0_iobuf_close(in, NULL);
1170         return 1;
1171
1172 fail:
1173         d0_iobuf_close(in, NULL);
1174         return 0;
1175 }
1176
1177 D0_WARN_UNUSED_RESULT D0_BOOL d0_blind_id_fingerprint64_public_id(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
1178 {
1179         d0_iobuf_t *out = NULL;
1180         static unsigned char convbuf[1024];
1181         d0_iobuf_t *conv = NULL;
1182         size_t sz, n;
1183
1184         USING(rsa_n);
1185         USING(rsa_e);
1186         USING(schnorr_g_to_s);
1187
1188         out = d0_iobuf_open_write(outbuf, *outbuflen);
1189         conv = d0_iobuf_open_write(convbuf, sizeof(convbuf));
1190
1191         CHECK(d0_iobuf_write_bignum(conv, ctx->rsa_n));
1192         CHECK(d0_iobuf_write_bignum(conv, ctx->rsa_e));
1193         CHECK(d0_iobuf_write_bignum(conv, ctx->schnorr_g_to_s));
1194         CHECK(d0_iobuf_close(conv, &sz));
1195         conv = NULL;
1196
1197         n = (*outbuflen / 4) * 3;
1198         if(n > SHA_DIGESTSIZE)
1199                 n = SHA_DIGESTSIZE;
1200         CHECK(d0_iobuf_write_raw(out, sha(convbuf, sz), n) == n);
1201         CHECK(d0_iobuf_conv_base64_out(out));
1202
1203         return d0_iobuf_close(out, outbuflen);
1204
1205 fail:
1206         if(conv)
1207                 d0_iobuf_close(conv, &sz);
1208         d0_iobuf_close(out, outbuflen);
1209         return 0;
1210 }
1211
1212 D0_BOOL d0_blind_id_sessionkey_public_id(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
1213 {
1214         USING(t); USING(other_g_to_t); USING(schnorr_G);
1215
1216         // temps: temp0 result
1217         CHECK(d0_bignum_mod_pow(temp0, ctx->other_g_to_t, ctx->t, ctx->schnorr_G));
1218         return d0_longhash_bignum(temp0, (unsigned char *) outbuf, *outbuflen);
1219
1220 fail:
1221         return 0;
1222 }
1223
1224 d0_blind_id_t *d0_blind_id_new(void)
1225 {
1226         d0_blind_id_t *b = d0_malloc(sizeof(d0_blind_id_t));
1227         memset(b, 0, sizeof(*b));
1228         return b;
1229 }
1230
1231 void d0_blind_id_free(d0_blind_id_t *a)
1232 {
1233         d0_blind_id_clear(a);
1234         d0_free(a);
1235 }
1236
1237 void d0_blind_id_util_sha256(char *out, const char *in, size_t n)
1238 {
1239         SHA256_CTX context;
1240         SHA256_Init(&context);
1241         SHA256_Update(&context, (const unsigned char *) in, n);
1242         return SHA256_Final((unsigned char *) out, &context);
1243 }