]> de.git.xonotic.org Git - xonotic/d0_blind_id.git/blob - d0_blind_id.c
more bugfixes, SSL variant works now
[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         MPCHECK(d0_bignum_mod_pow(temp0, four, ctx->r, ctx->schnorr_G));
751         MPCHECK_ASSIGN(ctx->g_to_t, d0_bignum_mod_pow(ctx->g_to_t, four, ctx->t, ctx->schnorr_G));
752         CHECK(!failed);
753
754         // hash it, hash it, everybody hash it
755         conv = d0_iobuf_open_write(convbuf, sizeof(convbuf));
756         CHECK(d0_iobuf_write_bignum(conv, temp0));
757         CHECK(d0_iobuf_write_bignum(conv, ctx->g_to_t));
758         CHECK(d0_iobuf_write_packet(conv, msg, msglen));
759         CHECK(d0_iobuf_write_bignum(conv, temp0));
760         CHECK(d0_iobuf_write_bignum(conv, ctx->g_to_t));
761         d0_iobuf_close(conv, &sz);
762         conv = NULL;
763         CHECK(d0_iobuf_write_raw(out, sha(convbuf, sz), SCHNORR_HASHSIZE) == SCHNORR_HASHSIZE);
764         CHECK(d0_iobuf_write_packet(out, msg, msglen));
765
766         return d0_iobuf_close(out, outbuflen);
767
768 fail:
769         d0_iobuf_close(out, outbuflen);
770         return 0;
771 }
772
773 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)
774 //   first run: get 4^s, 4^s signature
775 //   1. check sig
776 //   2. save HASH(4^r)
777 //   3. send challenge challenge of SCHNORR_BITS
778 {
779         d0_iobuf_t *in = NULL;
780         d0_iobuf_t *out = NULL;
781         static unsigned char shabuf[2048];
782         size_t sz;
783
784         // temps: temp0 order, temp0 signature check
785         if(is_first)
786         {
787                 REPLACING(schnorr_g_to_s); REPLACING(schnorr_H_g_to_s_signature);
788                 if(recv_modulus)
789                         REPLACING(schnorr_G);
790                 else
791                         USING(schnorr_G);
792         }
793         else
794         {
795                 USING(schnorr_g_to_s); USING(schnorr_H_g_to_s_signature);
796                 USING(schnorr_G);
797         }
798         USING(rsa_e); USING(rsa_n);
799         REPLACING(challenge); REPLACING(msg); REPLACING(msglen); REPLACING(msghash); REPLACING(r); REPLACING(t);
800
801         in = d0_iobuf_open_read(inbuf, inbuflen);
802         out = d0_iobuf_open_write(outbuf, *outbuflen);
803
804         if(is_first)
805         {
806                 if(recv_modulus)
807                 {
808                         CHECK_ASSIGN(ctx->schnorr_G, d0_iobuf_read_bignum(in, ctx->schnorr_G));
809                         CHECK(d0_bignum_cmp(ctx->schnorr_G, zero) > 0);
810                         CHECK(d0_bignum_cmp(ctx->schnorr_G, ctx->rsa_n) < 0);
811                 }
812                 CHECK_ASSIGN(ctx->schnorr_g_to_s, d0_iobuf_read_bignum(in, ctx->schnorr_g_to_s));
813                 CHECK(d0_bignum_cmp(ctx->schnorr_g_to_s, zero) >= 0);
814                 CHECK(d0_bignum_cmp(ctx->schnorr_g_to_s, ctx->schnorr_G) < 0);
815                 CHECK_ASSIGN(ctx->schnorr_H_g_to_s_signature, d0_iobuf_read_bignum(in, ctx->schnorr_H_g_to_s_signature));
816                 CHECK(d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, zero) >= 0);
817                 CHECK(d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, ctx->rsa_n) < 0);
818
819                 // check signature of key (t = k^d, so, t^challenge = k)
820                 CHECK(d0_bignum_mod_pow(temp0, ctx->schnorr_H_g_to_s_signature, ctx->rsa_e, ctx->rsa_n));
821
822                 // we will actually sign SHA(4^s) to prevent a malleability attack!
823                 CHECK(d0_bignum_mov(temp2, ctx->schnorr_g_to_s));
824                 sz = (d0_bignum_size(ctx->rsa_n) + 7) / 8; // this is too long, so we have to take the value % rsa_n when "decrypting"
825                 if(sz > sizeof(shabuf))
826                         sz = sizeof(shabuf);
827                 CHECK(d0_longhash_destructive(temp2, shabuf, sz));
828                 CHECK(d0_bignum_import_unsigned(temp2, shabuf, sz));
829
830                 // + 7 / 8 is too large, so let's mod it
831                 CHECK(d0_bignum_divmod(NULL, temp1, temp2, ctx->rsa_n));
832
833                 // hash complete
834                 if(d0_bignum_cmp(temp0, temp1))
835                 {
836                         // accept the key anyway, but mark as failed signature! will later return 0 in status
837                         CHECK(d0_bignum_zero(ctx->schnorr_H_g_to_s_signature));
838                 }
839         }
840
841         CHECK(d0_iobuf_read_raw(in, ctx->msghash, SCHNORR_HASHSIZE));
842         ctx->msglen = MSGSIZE;
843         CHECK(d0_iobuf_read_packet(in, ctx->msg, &ctx->msglen));
844
845         // send challenge
846         CHECK_ASSIGN(ctx->challenge, d0_bignum_rand_bit_atmost(ctx->challenge, SCHNORR_BITS));
847         CHECK(d0_iobuf_write_bignum(out, ctx->challenge));
848
849         // Diffie Hellmann send
850         CHECK(d0_dl_get_order(temp0, ctx->schnorr_G));
851         CHECK_ASSIGN(ctx->t, d0_bignum_rand_range(ctx->t, zero, temp0));
852         CHECK(d0_bignum_mod_pow(temp0, four, ctx->t, ctx->schnorr_G));
853         CHECK(d0_iobuf_write_bignum(out, temp0));
854
855         if(status)
856                 *status = !!d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, zero);
857
858         d0_iobuf_close(in, NULL);
859         return d0_iobuf_close(out, outbuflen);
860
861 fail:
862         d0_iobuf_close(in, NULL);
863         d0_iobuf_close(out, outbuflen);
864         return 0;
865 }
866
867 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)
868 //   1. read challenge challenge of SCHNORR_BITS
869 //   2. reply with r + s * challenge mod order
870 {
871         d0_iobuf_t *in = NULL;
872         d0_iobuf_t *out = NULL;
873
874         // temps: 0 order, 1 prod, 2 y, 3 challenge
875         REPLACING(other_g_to_t); REPLACING(t);
876         USING(schnorr_G); USING(schnorr_s); USING(r); USING(g_to_t);
877
878         in = d0_iobuf_open_read(inbuf, inbuflen);
879         out = d0_iobuf_open_write(outbuf, *outbuflen);
880
881         CHECK(d0_iobuf_read_bignum(in, temp3));
882         CHECK(d0_bignum_cmp(temp3, zero) >= 0);
883         CHECK(d0_bignum_size(temp3) <= SCHNORR_BITS);
884
885         // send response for schnorr ID scheme
886         // i.challenge. r + ctx->schnorr_s * temp3
887         CHECK(d0_dl_get_order(temp0, ctx->schnorr_G));
888         CHECK(d0_bignum_mod_mul(temp1, ctx->schnorr_s, temp3, temp0));
889         CHECK(d0_bignum_mod_add(temp2, temp1, ctx->r, temp0));
890         CHECK(d0_iobuf_write_bignum(out, temp2));
891
892         // Diffie Hellmann recv
893         CHECK_ASSIGN(ctx->other_g_to_t, d0_iobuf_read_bignum(in, ctx->other_g_to_t));
894         CHECK(d0_bignum_cmp(ctx->other_g_to_t, zero) > 0);
895         CHECK(d0_bignum_cmp(ctx->other_g_to_t, ctx->schnorr_G) < 0);
896         // Diffie Hellmann send
897         CHECK(d0_iobuf_write_bignum(out, ctx->g_to_t));
898
899         d0_iobuf_close(in, NULL);
900         return d0_iobuf_close(out, outbuflen);
901
902 fail:
903         d0_iobuf_close(in, NULL);
904         d0_iobuf_close(out, outbuflen);
905         return 0;
906 }
907
908 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)
909 //   1. read y = r + s * challenge mod order
910 //   2. verify: g^y (g^s)^-challenge = g^(r+s*challenge-s*challenge) = g^r
911 //      (check using H(g^r) which we know)
912 {
913         d0_iobuf_t *in = NULL;
914         static unsigned char convbuf[1024];
915         d0_iobuf_t *conv = NULL;
916         size_t sz;
917
918         // temps: 0 y 1 order
919         USING(challenge); USING(schnorr_G);
920         REPLACING(other_g_to_t);
921
922         in = d0_iobuf_open_read(inbuf, inbuflen);
923
924         CHECK(d0_dl_get_order(temp1, ctx->schnorr_G));
925         CHECK(d0_iobuf_read_bignum(in, temp0));
926         CHECK(d0_bignum_cmp(temp0, zero) >= 0);
927         CHECK(d0_bignum_cmp(temp0, temp1) < 0);
928
929         // verify schnorr ID scheme
930         // we need 4^r = 4^temp0 (g^s)^-challenge
931         CHECK(d0_bignum_mod_inv(temp1, ctx->schnorr_g_to_s, ctx->schnorr_G));
932         CHECK(d0_bignum_mod_pow(temp2, temp1, ctx->challenge, ctx->schnorr_G));
933         CHECK(d0_bignum_mod_pow(temp1, four, temp0, ctx->schnorr_G));
934         CHECK_ASSIGN(temp3, d0_bignum_mod_mul(temp3, temp1, temp2, ctx->schnorr_G));
935
936         // Diffie Hellmann recv
937         CHECK_ASSIGN(ctx->other_g_to_t, d0_iobuf_read_bignum(in, ctx->other_g_to_t));
938         CHECK(d0_bignum_cmp(ctx->other_g_to_t, zero) > 0);
939         CHECK(d0_bignum_cmp(ctx->other_g_to_t, ctx->schnorr_G) < 0);
940
941         // hash it, hash it, everybody hash it
942         conv = d0_iobuf_open_write(convbuf, sizeof(convbuf));
943         CHECK(d0_iobuf_write_bignum(conv, temp3));
944         CHECK(d0_iobuf_write_bignum(conv, ctx->other_g_to_t));
945         CHECK(d0_iobuf_write_packet(conv, ctx->msg, ctx->msglen));
946         CHECK(d0_iobuf_write_bignum(conv, temp3));
947         CHECK(d0_iobuf_write_bignum(conv, ctx->other_g_to_t));
948         d0_iobuf_close(conv, &sz);
949         conv = NULL;
950         if(memcmp(sha(convbuf, sz), ctx->msghash, SCHNORR_HASHSIZE))
951         {
952                 // FAIL (not owned by player)
953                 goto fail;
954         }
955
956         if(status)
957                 *status = !!d0_bignum_cmp(ctx->schnorr_H_g_to_s_signature, zero);
958
959         if(ctx->msglen <= *msglen)
960                 memcpy(msg, ctx->msg, ctx->msglen);
961         else
962                 memcpy(msg, ctx->msg, *msglen);
963         *msglen = ctx->msglen;
964
965         d0_iobuf_close(in, NULL);
966         return 1;
967
968 fail:
969         d0_iobuf_close(in, NULL);
970         return 0;
971 }
972
973 WARN_UNUSED_RESULT BOOL d0_blind_id_authenticate_with_private_id_generate_missing_signature(d0_blind_id_t *ctx)
974 {
975         size_t sz;
976         static unsigned char shabuf[2048];
977
978         REPLACING(schnorr_H_g_to_s_signature);
979         USING(schnorr_g_to_s); USING(rsa_d); USING(rsa_n);
980
981         // we will actually sign SHA(4^s) to prevent a malleability attack!
982         CHECK(d0_bignum_mov(temp2, ctx->schnorr_g_to_s));
983         sz = (d0_bignum_size(ctx->rsa_n) + 7) / 8; // this is too long, so we have to take the value % rsa_n when "decrypting"
984         if(sz > sizeof(shabuf))
985                 sz = sizeof(shabuf);
986         CHECK(d0_longhash_destructive(temp2, shabuf, sz));
987         CHECK(d0_bignum_import_unsigned(temp2, shabuf, sz));
988
989         // + 7 / 8 is too large, so let's mod it
990         CHECK(d0_bignum_divmod(NULL, temp1, temp2, ctx->rsa_n));
991         CHECK(d0_bignum_mod_pow(ctx->schnorr_H_g_to_s_signature, temp1, ctx->rsa_d, ctx->rsa_n));
992         return 1;
993
994 fail:
995         return 0;
996 }
997
998 WARN_UNUSED_RESULT BOOL d0_blind_id_fingerprint64_public_id(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
999 {
1000         d0_iobuf_t *out = NULL;
1001         static unsigned char convbuf[1024];
1002         d0_iobuf_t *conv = NULL;
1003         size_t sz, n;
1004
1005         USING(rsa_n);
1006         USING(rsa_e);
1007         USING(schnorr_g_to_s);
1008
1009         out = d0_iobuf_open_write(outbuf, *outbuflen);
1010         conv = d0_iobuf_open_write(convbuf, sizeof(convbuf));
1011
1012         CHECK(d0_iobuf_write_bignum(conv, ctx->rsa_n));
1013         CHECK(d0_iobuf_write_bignum(conv, ctx->rsa_e));
1014         CHECK(d0_iobuf_write_bignum(conv, ctx->schnorr_g_to_s));
1015         CHECK(d0_iobuf_close(conv, &sz));
1016         conv = NULL;
1017
1018         n = (*outbuflen / 4) * 3;
1019         if(n > SHA_DIGESTSIZE)
1020                 n = SHA_DIGESTSIZE;
1021         CHECK(d0_iobuf_write_raw(out, sha(convbuf, sz), n) == n);
1022         CHECK(d0_iobuf_conv_base64_out(out));
1023
1024         return d0_iobuf_close(out, outbuflen);
1025
1026 fail:
1027         if(conv)
1028                 d0_iobuf_close(conv, &sz);
1029         d0_iobuf_close(out, outbuflen);
1030         return 0;
1031 }
1032
1033 BOOL d0_blind_id_sessionkey_public_id(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
1034 {
1035         USING(t); USING(other_g_to_t); USING(schnorr_G);
1036
1037         // temps: temp0 result
1038         CHECK(d0_bignum_mod_pow(temp0, ctx->other_g_to_t, ctx->t, ctx->schnorr_G));
1039         return d0_longhash_destructive(temp0, outbuf, *outbuflen);
1040
1041 fail:
1042         return 0;
1043 }
1044
1045 d0_blind_id_t *d0_blind_id_new(void)
1046 {
1047         d0_blind_id_t *b = d0_malloc(sizeof(d0_blind_id_t));
1048         memset(b, 0, sizeof(*b));
1049         return b;
1050 }
1051
1052 void d0_blind_id_free(d0_blind_id_t *a)
1053 {
1054         d0_blind_id_clear(a);
1055         d0_free(a);
1056 }
1057
1058 void d0_blind_id_util_sha256(char *out, const char *in, size_t n)
1059 {
1060         SHA256_CTX context;
1061         SHA256_Init(&context);
1062         SHA256_Update(&context, (const unsigned char *) in, n);
1063         return SHA256_Final((unsigned char *) out, &context);
1064 }