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