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