Line data Source code
1 : #include "bbs.h"
2 : #include "bbs_util.h"
3 : #include <relic.h>
4 :
5 : // Magic constants to be used as Domain Separation Tags
6 :
7 : #define BBS_SHA256_CIPHER_SUITE_ID "BBS_BLS12381G1_XMD:SHA-256_SSWU_RO_"
8 : #define BBS_SHA256_CIPHER_SUITE_LENGTH 35
9 : #define BBS_SHA256_DEFAULT_KEY_DST BBS_SHA256_CIPHER_SUITE_ID "KEYGEN_DST_"
10 : #define BBS_SHA256_DEFAULT_KEY_DST_LENGTH BBS_SHA256_CIPHER_SUITE_LENGTH + 11
11 : #define BBS_SHA256_API_ID BBS_SHA256_CIPHER_SUITE_ID "H2G_HM2S_"
12 : #define BBS_SHA256_API_ID_LENGTH BBS_SHA256_CIPHER_SUITE_LENGTH + 9
13 : #define BBS_SHA256_SIGNATURE_DST BBS_SHA256_API_ID "H2S_"
14 : #define BBS_SHA256_SIGNATURE_DST_LENGTH BBS_SHA256_API_ID_LENGTH + 4
15 : #define BBS_SHA256_CHALLENGE_DST BBS_SHA256_API_ID "H2S_"
16 : #define BBS_SHA256_CHALLENGE_DST_LENGTH BBS_SHA256_API_ID_LENGTH + 4
17 : #define BBS_SHA256_MAP_DST BBS_SHA256_API_ID "MAP_MSG_TO_SCALAR_AS_HASH_"
18 : #define BBS_SHA256_MAP_DST_LENGTH BBS_SHA256_API_ID_LENGTH + 26
19 :
20 : // The above collision stems from the ID. Possible oversight? Should not compromise
21 : // security too much...
22 :
23 : #define BBS_SHAKE256_CIPHER_SUITE_ID "BBS_BLS12381G1_XOF:SHAKE-256_SSWU_RO_"
24 : #define BBS_SHAKE256_CIPHER_SUITE_LENGTH 37
25 : #define BBS_SHAKE256_DEFAULT_KEY_DST BBS_SHAKE256_CIPHER_SUITE_ID "KEYGEN_DST_"
26 : #define BBS_SHAKE256_DEFAULT_KEY_DST_LENGTH BBS_SHAKE256_CIPHER_SUITE_LENGTH + 11
27 : #define BBS_SHAKE256_API_ID BBS_SHAKE256_CIPHER_SUITE_ID "H2G_HM2S_"
28 : #define BBS_SHAKE256_API_ID_LENGTH BBS_SHAKE256_CIPHER_SUITE_LENGTH + 9
29 : #define BBS_SHAKE256_SIGNATURE_DST BBS_SHAKE256_API_ID "H2S_"
30 : #define BBS_SHAKE256_SIGNATURE_DST_LENGTH BBS_SHAKE256_API_ID_LENGTH + 4
31 : #define BBS_SHAKE256_CHALLENGE_DST BBS_SHAKE256_API_ID "H2S_"
32 : #define BBS_SHAKE256_CHALLENGE_DST_LENGTH BBS_SHAKE256_API_ID_LENGTH + 4
33 : #define BBS_SHAKE256_MAP_DST BBS_SHAKE256_API_ID "MAP_MSG_TO_SCALAR_AS_HASH_"
34 : #define BBS_SHAKE256_MAP_DST_LENGTH BBS_SHAKE256_API_ID_LENGTH + 26
35 :
36 : // *INDENT-OFF* - Preserve formatting
37 : bbs_cipher_suite_t bbs_sha256_cipher_suite_s = {
38 : .p1 = {
39 : 0xa8, 0xce, 0x25, 0x61, 0x02, 0x84, 0x08, 0x21, 0xa3, 0xe9, 0x4e, 0xa9, 0x02, 0x5e, 0x46,
40 : 0x62, 0xb2, 0x05, 0x76, 0x2f, 0x97, 0x76, 0xb3, 0xa7, 0x66, 0xc8, 0x72, 0xb9, 0x48, 0xf1,
41 : 0xfd, 0x22, 0x5e, 0x7c, 0x59, 0x69, 0x85, 0x88, 0xe7, 0x0d, 0x11, 0x40, 0x6d, 0x16, 0x1b,
42 : 0x4e, 0x28, 0xc9
43 : },
44 : .expand_message_init = expand_message_init_sha256,
45 : .expand_message_update = expand_message_update_sha256,
46 : .expand_message_finalize_48B = expand_message_finalize_48B_sha256,
47 : .expand_message_dyn = expand_message_dyn_sha256,
48 : .cipher_suite_id = (char*) BBS_SHA256_CIPHER_SUITE_ID,
49 : .cipher_suite_id_len = BBS_SHA256_CIPHER_SUITE_LENGTH,
50 : .default_key_dst = BBS_SHA256_DEFAULT_KEY_DST,
51 : .default_key_dst_len = BBS_SHA256_DEFAULT_KEY_DST_LENGTH,
52 : .api_id = BBS_SHA256_API_ID,
53 : .api_id_len = BBS_SHA256_API_ID_LENGTH,
54 : .signature_dst = BBS_SHA256_SIGNATURE_DST,
55 : .signature_dst_len = BBS_SHA256_SIGNATURE_DST_LENGTH,
56 : .challenge_dst = BBS_SHA256_CHALLENGE_DST,
57 : .challenge_dst_len = BBS_SHA256_CHALLENGE_DST_LENGTH,
58 : .map_dst = BBS_SHA256_MAP_DST,
59 : .map_dst_len = BBS_SHA256_MAP_DST_LENGTH,
60 : };
61 : bbs_cipher_suite_t *bbs_sha256_cipher_suite = &bbs_sha256_cipher_suite_s;
62 :
63 : bbs_cipher_suite_t bbs_shake256_cipher_suite_s = {
64 : .p1 = {
65 : 0x89, 0x29, 0xdf, 0xbc, 0x7e, 0x66, 0x42, 0xc4, 0xed, 0x9c, 0xba, 0x08, 0x56, 0xe4, 0x93,
66 : 0xf8, 0xb9, 0xd7, 0xd5, 0xfc, 0xb0, 0xc3, 0x1e, 0xf8, 0xfd, 0xcd, 0x34, 0xd5, 0x06, 0x48,
67 : 0xa5, 0x6c, 0x79, 0x5e, 0x10, 0x6e, 0x9e, 0xad, 0xa6, 0xe0, 0xbd, 0xa3, 0x86, 0xb4, 0x14,
68 : 0x15, 0x07, 0x55
69 : },
70 : .expand_message_init = expand_message_init_shake256,
71 : .expand_message_update = expand_message_update_shake256,
72 : .expand_message_finalize_48B = expand_message_finalize_48B_shake256,
73 : .expand_message_dyn = expand_message_dyn_shake256,
74 : .cipher_suite_id = (char*) BBS_SHAKE256_CIPHER_SUITE_ID,
75 : .cipher_suite_id_len = BBS_SHAKE256_CIPHER_SUITE_LENGTH,
76 : .default_key_dst = BBS_SHAKE256_DEFAULT_KEY_DST,
77 : .default_key_dst_len = BBS_SHAKE256_DEFAULT_KEY_DST_LENGTH,
78 : .api_id = BBS_SHAKE256_API_ID,
79 : .api_id_len = BBS_SHAKE256_API_ID_LENGTH,
80 : .signature_dst = BBS_SHAKE256_SIGNATURE_DST,
81 : .signature_dst_len = BBS_SHAKE256_SIGNATURE_DST_LENGTH,
82 : .challenge_dst = BBS_SHAKE256_CHALLENGE_DST,
83 : .challenge_dst_len = BBS_SHAKE256_CHALLENGE_DST_LENGTH,
84 : .map_dst = BBS_SHAKE256_MAP_DST,
85 : .map_dst_len = BBS_SHAKE256_MAP_DST_LENGTH,
86 : };
87 : bbs_cipher_suite_t *bbs_shake256_cipher_suite = &bbs_shake256_cipher_suite_s;
88 : // *INDENT-ON* - Restore formatting
89 :
90 : int
91 2 : bbs_keygen_full (
92 : bbs_cipher_suite_t *cipher_suite,
93 : bbs_secret_key sk,
94 : bbs_public_key pk
95 : )
96 : {
97 2 : int res = BBS_ERROR;
98 : static uint8_t seed[32];
99 :
100 : // Gather randomness
101 : RLC_TRY {
102 2 : rand_bytes (seed, 32);
103 : }
104 : RLC_CATCH_ANY {
105 : goto cleanup;
106 : }
107 :
108 : // Generate the secret key
109 2 : if (BBS_OK != bbs_keygen (cipher_suite, sk, seed, 32, 0, 0, 0, 0))
110 : {
111 0 : goto cleanup;
112 : }
113 :
114 : // Generate the public key
115 2 : if (BBS_OK != bbs_sk_to_pk (cipher_suite, sk, pk))
116 : {
117 0 : goto cleanup;
118 : }
119 :
120 2 : res = BBS_OK;
121 2 : cleanup:
122 2 : return res;
123 : }
124 :
125 :
126 : int
127 4 : bbs_keygen (
128 : bbs_cipher_suite_t *cipher_suite,
129 : bbs_secret_key sk,
130 : const uint8_t *key_material,
131 : uint16_t key_material_len,
132 : const uint8_t *key_info,
133 : uint16_t key_info_len,
134 : const uint8_t *key_dst,
135 : uint8_t key_dst_len
136 : )
137 : {
138 : bn_t sk_n;
139 4 : uint16_t key_info_len_be = ((key_info_len & 0x00FFu) << 8) | (key_info_len >> 8);
140 4 : int res = BBS_ERROR;
141 :
142 : bn_null (sk_n);
143 :
144 4 : if (! key_info)
145 : {
146 2 : key_info = (uint8_t*) "";
147 2 : key_info_len = 0;
148 : }
149 :
150 4 : if (! key_dst)
151 : {
152 2 : key_dst = (uint8_t*) cipher_suite->default_key_dst;
153 2 : key_dst_len = cipher_suite->default_key_dst_len;
154 : }
155 :
156 : RLC_TRY {
157 4 : bn_new (sk_n);
158 : }
159 : RLC_CATCH_ANY {
160 : goto cleanup;
161 : }
162 :
163 4 : if (BBS_OK != hash_to_scalar (cipher_suite,
164 : sk_n,
165 : key_dst,
166 : key_dst_len,
167 : 3,
168 : key_material,
169 : (uint32_t) key_material_len,
170 : &key_info_len_be,
171 : (uint32_t) 2,
172 : key_info,
173 : (uint32_t) key_info_len))
174 : {
175 0 : goto cleanup;
176 : }
177 :
178 : // Serialize
179 : RLC_TRY {
180 4 : bn_write_bin (sk, BBS_SK_LEN, sk_n);
181 : }
182 : RLC_CATCH_ANY {
183 : goto cleanup;
184 : }
185 :
186 4 : res = BBS_OK;
187 4 : cleanup:
188 : bn_free (sk_n);
189 4 : return res;
190 : }
191 :
192 : int
193 20 : bbs_init (void)
194 : {
195 20 : if (core_init () != RLC_OK)
196 : {
197 0 : core_clean ();
198 0 : return 1;
199 : }
200 20 : if (pc_param_set_any () != RLC_OK)
201 : {
202 0 : core_clean ();
203 0 : return 1;
204 : }
205 20 : return 0;
206 : }
207 :
208 : int
209 0 : bbs_deinit (void)
210 : {
211 0 : core_clean ();
212 0 : return 0;
213 : }
214 :
215 : int
216 4 : bbs_sk_to_pk (
217 : bbs_cipher_suite_t *cipher_suite,
218 : const bbs_secret_key sk,
219 : bbs_public_key pk
220 : )
221 : {
222 4 : int res = BBS_ERROR;
223 : bn_t sk_n;
224 : ep2_t pk_p;
225 :
226 : bn_null (sk_n);
227 : ep2_null (pk_p);
228 :
229 : RLC_TRY {
230 4 : bn_new (sk_n);
231 : ep2_new (pk_p);
232 4 : bn_read_bbs (sk_n, sk);
233 4 : ep2_mul_gen (pk_p, sk_n);
234 4 : ep2_write_bbs (pk, pk_p);
235 : }
236 : RLC_CATCH_ANY {
237 : goto cleanup;
238 : }
239 :
240 4 : res = BBS_OK;
241 4 : cleanup:
242 : bn_free (sk_n);
243 : ep2_free (pk_p);
244 4 : return res;
245 : }
246 :
247 :
248 : int
249 6 : bbs_sign (
250 : bbs_cipher_suite_t *cipher_suite,
251 : const bbs_secret_key sk,
252 : const bbs_public_key pk,
253 : bbs_signature signature,
254 : const uint8_t *header,
255 : uint64_t header_len,
256 : uint64_t num_messages,
257 : ...
258 : )
259 : {
260 : va_list ap;
261 : uint8_t generator_ctx[48 + 8];
262 : uint8_t buffer[BBS_SCALAR_LEN];
263 : bn_t e, domain, msg_scalar, sk_n;
264 : ep_t A, B, Q_1, H_i;
265 : uint8_t *msg;
266 : uint32_t msg_len;
267 : union bbs_hash_context dom_ctx, ch_ctx;
268 6 : int res = BBS_ERROR;
269 :
270 6 : va_start (ap, num_messages);
271 : bn_null (e);
272 : bn_null (sk_n);
273 : bn_null (domain);
274 : bn_null (msg_scalar);
275 : ep_null (A);
276 : ep_null (B);
277 : ep_null (Q_1);
278 : ep_null (H_i);
279 :
280 6 : if (! header)
281 : {
282 0 : header = (uint8_t*) "";
283 0 : header_len = 0;
284 : }
285 :
286 6 : if (BBS_OK != create_generator_init (cipher_suite,
287 : generator_ctx,
288 6 : (uint8_t*) cipher_suite->api_id,
289 6 : cipher_suite->api_id_len))
290 : {
291 0 : goto cleanup;
292 : }
293 6 : if (BBS_OK != calculate_domain_init (cipher_suite, &dom_ctx, pk, num_messages))
294 : {
295 0 : goto cleanup;
296 : }
297 6 : if (BBS_OK != hash_to_scalar_init (cipher_suite, &ch_ctx))
298 : {
299 0 : goto cleanup;
300 : }
301 :
302 6 : if (BBS_OK != hash_to_scalar_update (cipher_suite, &ch_ctx, sk, BBS_SK_LEN))
303 : {
304 0 : goto cleanup;
305 : }
306 : RLC_TRY {
307 6 : bn_new (e);
308 6 : bn_new (sk_n);
309 6 : bn_new (domain);
310 6 : bn_new (msg_scalar);
311 : ep_new (A);
312 : ep_new (B);
313 : ep_new (Q_1);
314 : ep_new (H_i);
315 :
316 : // Initialize B to P1
317 6 : ep_read_bbs (B, cipher_suite->p1);
318 : }
319 : RLC_CATCH_ANY {
320 : goto cleanup;
321 : }
322 :
323 : // Calculate Q_1
324 6 : if (BBS_OK != create_generator_next (cipher_suite,
325 : generator_ctx,
326 : Q_1,
327 6 : (uint8_t*) cipher_suite->api_id,
328 6 : cipher_suite->api_id_len))
329 : {
330 0 : goto cleanup;
331 : }
332 6 : if (BBS_OK != calculate_domain_update (cipher_suite, &dom_ctx, Q_1))
333 : {
334 0 : goto cleanup;
335 : }
336 :
337 32 : for (uint64_t i = 0; i<num_messages; i++)
338 : {
339 : // Calculate H_i
340 26 : if (BBS_OK != create_generator_next (cipher_suite, generator_ctx, H_i,
341 26 : (uint8_t*) cipher_suite->api_id,
342 26 : cipher_suite->api_id_len)
343 : )
344 : {
345 0 : goto cleanup;
346 : }
347 26 : if (BBS_OK != calculate_domain_update (cipher_suite, &dom_ctx, H_i))
348 : {
349 0 : goto cleanup;
350 : }
351 :
352 : // Calculate msg_scalar (oneshot)
353 26 : msg = va_arg (ap, uint8_t*);
354 26 : msg_len = va_arg (ap, uint32_t);
355 26 : if (BBS_OK != hash_to_scalar (cipher_suite, msg_scalar,
356 26 : (uint8_t*) cipher_suite->map_dst,
357 26 : cipher_suite->map_dst_len, 1, msg,
358 : (uint32_t) msg_len))
359 : {
360 0 : goto cleanup;
361 : }
362 : RLC_TRY {
363 : // Update B
364 26 : ep_mul (H_i, H_i, msg_scalar);
365 26 : ep_add (B, B, H_i);
366 :
367 : // Serialize msg_scalar for hashing into e
368 26 : bn_write_bbs (buffer, msg_scalar);
369 : }
370 : RLC_CATCH_ANY {
371 : goto cleanup;
372 : }
373 26 : if (BBS_OK != hash_to_scalar_update (cipher_suite, &ch_ctx, buffer, BBS_SCALAR_LEN))
374 : {
375 0 : goto cleanup;
376 : }
377 : }
378 6 : if (BBS_OK != calculate_domain_finalize (cipher_suite,
379 : &dom_ctx,
380 : domain,
381 : header,
382 : header_len,
383 6 : (uint8_t*) cipher_suite->api_id,
384 6 : cipher_suite->api_id_len))
385 : {
386 0 : goto cleanup;
387 : }
388 :
389 : // Derive e
390 : RLC_TRY {
391 6 : bn_write_bbs (buffer, domain);
392 : }
393 : RLC_CATCH_ANY {
394 : goto cleanup;
395 : }
396 6 : if (BBS_OK != hash_to_scalar_update (cipher_suite, &ch_ctx, buffer, BBS_SCALAR_LEN))
397 : {
398 0 : goto cleanup;
399 : }
400 6 : if (BBS_OK != hash_to_scalar_finalize (cipher_suite,
401 : &ch_ctx,
402 : e,
403 6 : (uint8_t*) cipher_suite->signature_dst,
404 6 : cipher_suite->signature_dst_len))
405 : {
406 0 : goto cleanup;
407 : }
408 :
409 : RLC_TRY {
410 : // Update B
411 6 : ep_mul (Q_1, Q_1, domain);
412 6 : ep_add (B, B, Q_1);
413 :
414 : // Calculate A
415 6 : bn_new (sk_n);
416 6 : bn_read_bbs (sk_n, sk);
417 6 : bn_add (sk_n, sk_n, e);
418 6 : bn_mod_inv (sk_n, sk_n, &(core_get ()->ep_r));
419 6 : ep_mul (A, B, sk_n);
420 :
421 : // Serialize (A,e)
422 6 : ep_write_bbs (signature, A);
423 6 : bn_write_bbs (signature + BBS_G1_ELEM_LEN, e);
424 : }
425 : RLC_CATCH_ANY {
426 : goto cleanup;
427 : }
428 :
429 6 : res = BBS_OK;
430 6 : cleanup:
431 : bn_free (e);
432 : bn_free (sk_n);
433 : bn_free (domain);
434 : bn_free (msg_scalar);
435 : ep_free (A);
436 : ep_free (B);
437 : ep_free (Q_1);
438 : ep_free (H_i);
439 6 : va_end (ap);
440 6 : return res;
441 : }
442 :
443 :
444 : int
445 6 : bbs_verify (
446 : bbs_cipher_suite_t *cipher_suite,
447 : const bbs_public_key pk,
448 : const bbs_signature signature,
449 : const uint8_t *header,
450 : uint64_t header_len,
451 : uint64_t num_messages,
452 : ...
453 : )
454 : {
455 : va_list ap;
456 : uint8_t generator_ctx[48 + 8];
457 : bn_t e, domain, msg_scalar;
458 : ep_t A, B, Q_1, H_i;
459 : ep2_t W, tmp_p;
460 : fp12_t paired1, paired2;
461 : uint8_t *msg;
462 : uint32_t msg_len;
463 : union bbs_hash_context dom_ctx;
464 6 : int res = BBS_ERROR;
465 :
466 6 : va_start (ap, num_messages);
467 : bn_null (e);
468 : bn_null (domain);
469 : bn_null (msg_scalar);
470 : ep_null (A);
471 : ep_null (B);
472 : ep_null (Q_1);
473 : ep_null (H_i);
474 : ep2_null (W);
475 : ep2_null (tmp_p);
476 : fp12_null (paired1);
477 : fp12_null (paired2);
478 :
479 6 : if (! header)
480 : {
481 0 : header = (uint8_t*) "";
482 0 : header_len = 0;
483 : }
484 :
485 6 : if (BBS_OK != create_generator_init (cipher_suite,
486 : generator_ctx,
487 6 : (uint8_t*) cipher_suite->api_id,
488 6 : cipher_suite->api_id_len))
489 : {
490 0 : goto cleanup;
491 : }
492 6 : if (BBS_OK != calculate_domain_init (cipher_suite, &dom_ctx, pk, num_messages))
493 : {
494 0 : goto cleanup;
495 : }
496 :
497 : RLC_TRY {
498 6 : bn_new (e);
499 6 : bn_new (domain);
500 6 : bn_new (msg_scalar);
501 : ep_new (A);
502 : ep_new (B);
503 : ep_new (Q_1);
504 : ep_new (H_i);
505 : ep2_new (W);
506 : ep2_new (tmp_p);
507 : fp12_new (paired1);
508 : fp12_new (paired2);
509 :
510 : // Initialize B to P1, and parse signature
511 6 : ep_read_bbs (B, cipher_suite->p1);
512 6 : ep_read_bbs (A, signature);
513 6 : bn_read_bbs (e, signature + BBS_G1_ELEM_LEN);
514 6 : ep2_read_bbs (W, pk);
515 : }
516 : RLC_CATCH_ANY {
517 : goto cleanup;
518 : }
519 :
520 : // Calculate Q_1
521 6 : if (BBS_OK != create_generator_next (cipher_suite,
522 : generator_ctx,
523 : Q_1,
524 6 : (uint8_t*) cipher_suite->api_id,
525 6 : cipher_suite->api_id_len))
526 : {
527 0 : goto cleanup;
528 : }
529 6 : if (BBS_OK != calculate_domain_update (cipher_suite, &dom_ctx, Q_1))
530 : {
531 0 : goto cleanup;
532 : }
533 :
534 32 : for (uint64_t i = 0; i<num_messages; i++)
535 : {
536 : // Calculate H_i
537 26 : if (BBS_OK != create_generator_next (cipher_suite, generator_ctx, H_i,
538 26 : (uint8_t*) cipher_suite->api_id,
539 26 : cipher_suite->api_id_len)
540 : )
541 : {
542 0 : goto cleanup;
543 : }
544 26 : if (BBS_OK != calculate_domain_update (cipher_suite, &dom_ctx, H_i))
545 : {
546 0 : goto cleanup;
547 : }
548 :
549 : // Calculate msg_scalar (oneshot)
550 26 : msg = va_arg (ap, uint8_t*);
551 26 : msg_len = va_arg (ap, uint32_t);
552 26 : if (BBS_OK != hash_to_scalar (cipher_suite, msg_scalar,
553 26 : (uint8_t*) cipher_suite->map_dst,
554 26 : cipher_suite->map_dst_len, 1, msg,
555 : (uint32_t) msg_len))
556 : {
557 0 : goto cleanup;
558 : }
559 : RLC_TRY {
560 : // Update B
561 26 : ep_mul (H_i, H_i, msg_scalar);
562 26 : ep_add (B, B, H_i);
563 : }
564 : RLC_CATCH_ANY {
565 : goto cleanup;
566 : }
567 : }
568 :
569 : // Finalize domain calculation
570 6 : if (BBS_OK != calculate_domain_finalize (cipher_suite,
571 : &dom_ctx,
572 : domain,
573 : header,
574 : header_len,
575 6 : (uint8_t*) cipher_suite->api_id,
576 6 : cipher_suite->api_id_len))
577 : {
578 0 : goto cleanup;
579 : }
580 : RLC_TRY {
581 : // Update B
582 6 : ep_mul (Q_1, Q_1, domain);
583 6 : ep_add (B, B, Q_1);
584 :
585 : // Compute pairings e(A, W + BP2 * e) * e(B, -BP2)
586 : // For valid signatures, this is the identity.
587 6 : ep2_mul_gen (tmp_p, e);
588 6 : ep2_add (tmp_p, W, tmp_p);
589 6 : pp_map_oatep_k12 (paired1, A, tmp_p);
590 :
591 6 : bn_set_dig (e, 1); // reuse e as -1
592 6 : bn_neg (e, e);
593 6 : ep2_mul_gen (tmp_p, e);
594 6 : pp_map_oatep_k12 (paired2, B, tmp_p);
595 :
596 6 : fp12_mul (paired1, paired1, paired2);
597 : }
598 : RLC_CATCH_ANY {
599 : goto cleanup;
600 : }
601 :
602 : // Check signature equation
603 6 : if (RLC_EQ != fp12_cmp_dig (paired1, 1))
604 : {
605 0 : goto cleanup;
606 : }
607 :
608 6 : res = BBS_OK;
609 6 : cleanup:
610 : bn_free (e);
611 : bn_free (domain);
612 : bn_free (msg_scalar);
613 : ep_free (A);
614 : ep_free (B);
615 : ep_free (Q_1);
616 : ep_free (H_i);
617 : ep2_free (W);
618 : ep2_free (tmp_p);
619 : fp12_free (paired1);
620 : fp12_free (paired2);
621 6 : va_end (ap);
622 6 : return res;
623 : }
624 :
625 :
626 : // bbs_proof_gen, but makes callbacks to prf for random scalars
627 : // We need to control the random scalars for the fixture tests. This way we do
628 : // not need to compile a dedicated library for the tests.
629 : int
630 8 : bbs_proof_gen_det (
631 : bbs_cipher_suite_t *cipher_suite,
632 : const bbs_public_key pk,
633 : const bbs_signature signature,
634 : uint8_t *proof,
635 : const uint8_t *header,
636 : uint64_t header_len,
637 : const uint8_t *presentation_header,
638 : uint64_t presentation_header_len,
639 : const uint64_t *disclosed_indexes,
640 : uint64_t disclosed_indexes_len,
641 : uint64_t num_messages,
642 : bbs_bn_prf prf,
643 : void *prf_cookie,
644 : va_list ap
645 : )
646 : {
647 : uint8_t generator_ctx[48 + 8];
648 : uint8_t T_buffer[2 * BBS_G1_ELEM_LEN];
649 : uint8_t scalar_buffer[BBS_SCALAR_LEN];
650 : uint8_t *proof_ptr, *msg;
651 : uint64_t msg_len, be_buffer;
652 : bn_t e, domain, msg_scalar, msg_scalar_tilde, r1, r2, e_tilde, r1_tilde,
653 : r3_tilde, challenge;
654 : ep_t A, B, Q_1, H_i, T1, T2, D, Abar, Bbar;
655 8 : uint64_t disclosed_indexes_idx = 0;
656 8 : uint64_t undisclosed_indexes_idx = 0;
657 8 : uint64_t undisclosed_indexes_len = num_messages - disclosed_indexes_len;
658 : union bbs_hash_context dom_ctx, ch_ctx;
659 8 : int res = BBS_ERROR;
660 :
661 8 : if (! header)
662 : {
663 0 : header = (uint8_t*) "";
664 0 : header_len = 0;
665 : }
666 :
667 8 : if (! presentation_header)
668 : {
669 0 : presentation_header = (uint8_t*) "";
670 0 : presentation_header_len = 0;
671 : }
672 :
673 : bn_null (e);
674 : bn_null (domain);
675 : bn_null (msg_scalar);
676 : bn_null (msg_scalar_tilde);
677 : bn_null (r1);
678 : bn_null (r2);
679 : bn_null (e_tilde);
680 : bn_null (r1_tilde);
681 : bn_null (r3_tilde);
682 : bn_null (challenge);
683 : ep_null (A);
684 : ep_null (B);
685 : ep_null (Q_1);
686 : ep_null (H_i);
687 : ep_null (T1);
688 : ep_null (T2);
689 : ep_null (D);
690 : ep_null (Abar);
691 : ep_null (Bbar);
692 :
693 8 : if (BBS_OK != create_generator_init (cipher_suite,
694 : generator_ctx,
695 8 : (uint8_t*) cipher_suite->api_id,
696 8 : cipher_suite->api_id_len))
697 : {
698 0 : goto cleanup;
699 : }
700 8 : if (BBS_OK != calculate_domain_init (cipher_suite, &dom_ctx, pk, num_messages))
701 : {
702 0 : goto cleanup;
703 : }
704 :
705 : RLC_TRY {
706 8 : bn_new (e);
707 8 : bn_new (domain);
708 8 : bn_new (msg_scalar);
709 8 : bn_new (msg_scalar_tilde);
710 8 : bn_new (r1);
711 8 : bn_new (r2);
712 8 : bn_new (e_tilde);
713 8 : bn_new (r1_tilde);
714 8 : bn_new (r3_tilde);
715 8 : bn_new (challenge);
716 : ep_new (A);
717 : ep_new (B);
718 : ep_new (Q_1);
719 : ep_new (H_i);
720 : ep_new (T1);
721 : ep_new (T2);
722 : ep_new (D);
723 : ep_new (Abar);
724 : ep_new (Bbar);
725 :
726 : // Initialize B to P1 and T2 to the identity
727 8 : ep_read_bbs (B, cipher_suite->p1);
728 8 : ep_set_infty (T2);
729 :
730 : // Parse the signature
731 8 : ep_read_bbs (A, signature);
732 8 : bn_read_bbs (e, signature + BBS_G1_ELEM_LEN);
733 : }
734 : RLC_CATCH_ANY {
735 : goto cleanup;
736 : }
737 :
738 : // Derive random scalars. The msg_scalar_tilde scalars are derived later
739 8 : if (BBS_OK != prf (cipher_suite, r1, 1, 0, prf_cookie))
740 0 : goto cleanup;
741 8 : if (BBS_OK != prf (cipher_suite, r2, 2, 0, prf_cookie))
742 0 : goto cleanup;
743 8 : if (BBS_OK != prf (cipher_suite, e_tilde, 3, 0, prf_cookie))
744 0 : goto cleanup;
745 8 : if (BBS_OK != prf (cipher_suite, r1_tilde, 4, 0, prf_cookie))
746 0 : goto cleanup;
747 8 : if (BBS_OK != prf (cipher_suite, r3_tilde, 5, 0, prf_cookie))
748 0 : goto cleanup;
749 :
750 : // Calculate Q_1
751 8 : if (BBS_OK != create_generator_next (cipher_suite,
752 : generator_ctx,
753 : Q_1,
754 8 : (uint8_t*) cipher_suite->api_id,
755 8 : cipher_suite->api_id_len))
756 : {
757 0 : goto cleanup;
758 : }
759 8 : if (BBS_OK != calculate_domain_update (cipher_suite, &dom_ctx, Q_1))
760 : {
761 0 : goto cleanup;
762 : }
763 :
764 : // Initialize Challenge Calculation
765 8 : if (BBS_OK != hash_to_scalar_init (cipher_suite, &ch_ctx))
766 : {
767 0 : goto cleanup;
768 : }
769 8 : be_buffer = UINT64_H2BE (disclosed_indexes_len);
770 8 : if (BBS_OK != hash_to_scalar_update (cipher_suite, &ch_ctx, (uint8_t*) &be_buffer, 8))
771 : {
772 0 : goto cleanup;
773 : }
774 :
775 : // Iterate over the messages
776 8 : proof_ptr = proof + 3 * BBS_G1_ELEM_LEN + 3 * BBS_SCALAR_LEN; // m_hat
777 54 : for (uint64_t i = 0; i<num_messages; i++)
778 : {
779 : // Calculate H_i
780 46 : if (BBS_OK != create_generator_next (cipher_suite, generator_ctx, H_i,
781 46 : (uint8_t*) cipher_suite->api_id,
782 46 : cipher_suite->api_id_len)
783 : )
784 : {
785 0 : goto cleanup;
786 : }
787 46 : if (BBS_OK != calculate_domain_update (cipher_suite, &dom_ctx, H_i))
788 : {
789 0 : goto cleanup;
790 : }
791 :
792 : // Calculate msg_scalar (oneshot)
793 46 : msg = va_arg (ap, uint8_t*);
794 46 : msg_len = va_arg (ap, uint32_t);
795 46 : if (BBS_OK != hash_to_scalar (cipher_suite, msg_scalar,
796 46 : (uint8_t*) cipher_suite->map_dst,
797 46 : cipher_suite->map_dst_len, 1, msg,
798 : (uint32_t) msg_len))
799 : {
800 0 : goto cleanup;
801 : }
802 : RLC_TRY {
803 : // Update B. Use Bbar as temporary buffer, because we
804 : // need H_i below
805 46 : ep_mul (Bbar, H_i, msg_scalar);
806 46 : ep_add (B, B, Bbar);
807 :
808 : // Write msg_scalar to the proof. This way, we do not
809 : // need to recalculate it later
810 46 : bn_write_bbs (proof_ptr, msg_scalar);
811 : }
812 : RLC_CATCH_ANY {
813 : goto cleanup;
814 : }
815 :
816 46 : if (disclosed_indexes_idx < disclosed_indexes_len && disclosed_indexes[
817 : disclosed_indexes_idx] == i)
818 : {
819 : // This message is disclosed. Update the challenge hash
820 32 : disclosed_indexes_idx++;
821 32 : be_buffer = UINT64_H2BE (i);
822 32 : if (BBS_OK != hash_to_scalar_update (cipher_suite, &ch_ctx,
823 : (uint8_t*) &be_buffer, 8))
824 : {
825 0 : goto cleanup;
826 : }
827 32 : if (BBS_OK != hash_to_scalar_update (cipher_suite, &ch_ctx, proof_ptr,
828 : BBS_SCALAR_LEN)
829 : )
830 : {
831 0 : goto cleanup;
832 : }
833 : }
834 : else
835 : {
836 : // This message is undisclosed. Derive new random scalar
837 : // and accumulate it onto T2
838 14 : if (BBS_OK != prf (cipher_suite, msg_scalar_tilde, 0,
839 : undisclosed_indexes_idx, prf_cookie)
840 : )
841 : {
842 0 : goto cleanup;
843 : }
844 :
845 : RLC_TRY {
846 : // Update T2
847 14 : ep_mul (H_i, H_i, msg_scalar_tilde);
848 14 : ep_add (T2, T2, H_i);
849 : }
850 : RLC_CATCH_ANY {
851 : goto cleanup;
852 : }
853 14 : undisclosed_indexes_idx++;
854 14 : proof_ptr += BBS_SCALAR_LEN; // Keep msg_scalar for later
855 : }
856 : }
857 :
858 : // Sanity check. If any indices for disclosed messages were out of order
859 : // or invalid, we fail here.
860 8 : if (disclosed_indexes_idx != disclosed_indexes_len)
861 : {
862 0 : goto cleanup;
863 : }
864 :
865 : // Finalize domain calculation
866 8 : if (BBS_OK != calculate_domain_finalize (cipher_suite,
867 : &dom_ctx,
868 : domain,
869 : header,
870 : header_len,
871 8 : (uint8_t*) cipher_suite->api_id,
872 8 : cipher_suite->api_id_len))
873 : {
874 0 : goto cleanup;
875 : }
876 : RLC_TRY {
877 : // Update B
878 8 : ep_mul (Q_1, Q_1, domain);
879 8 : ep_add (B, B, Q_1);
880 :
881 : // Calculate and write out D to proof
882 8 : ep_mul (D, B, r2);
883 8 : ep_write_bbs (proof + 2 * BBS_G1_ELEM_LEN, D);
884 :
885 : // Starting here, we no longer need B, so we use it as a
886 : // temporary variable.
887 :
888 : // Calculate and write out Abar to proof
889 8 : ep_mul (Abar, A, r1);
890 8 : ep_mul (Abar, Abar, r2);
891 8 : ep_write_bbs (proof, Abar);
892 :
893 : // Calculate and write out Bbar to proof
894 8 : ep_mul (Bbar, D, r1);
895 8 : ep_mul (B, Abar, e);
896 8 : ep_neg (B, B);
897 8 : ep_add (Bbar, Bbar, B);
898 8 : ep_write_bbs (proof + BBS_G1_ELEM_LEN, Bbar);
899 :
900 : // Calculate and write out T1 and T2 for the challenge
901 8 : ep_mul (B, D, r3_tilde);
902 8 : ep_add (T2, T2, B);
903 8 : ep_mul (T1, D, r1_tilde);
904 8 : ep_mul (B, Abar, e_tilde);
905 8 : ep_add (T1, T1, B);
906 8 : ep_write_bbs (T_buffer, T1);
907 8 : ep_write_bbs (T_buffer + BBS_G1_ELEM_LEN, T2);
908 :
909 : // Write out the domain. We reuse scalar_buffer
910 8 : bn_write_bbs (scalar_buffer, domain);
911 : }
912 : RLC_CATCH_ANY {
913 : goto cleanup;
914 : }
915 :
916 : // Finish calculating the challenge
917 8 : if (BBS_OK != hash_to_scalar_update (cipher_suite, &ch_ctx, proof, 3 * BBS_G1_ELEM_LEN))
918 : {
919 0 : goto cleanup;
920 : }
921 8 : if (BBS_OK != hash_to_scalar_update (cipher_suite, &ch_ctx, T_buffer, 2 * BBS_G1_ELEM_LEN))
922 : {
923 0 : goto cleanup;
924 : }
925 8 : if (BBS_OK != hash_to_scalar_update (cipher_suite, &ch_ctx, scalar_buffer, BBS_SCALAR_LEN))
926 : {
927 0 : goto cleanup;
928 : }
929 8 : be_buffer = UINT64_H2BE (presentation_header_len);
930 8 : if (BBS_OK != hash_to_scalar_update (cipher_suite, &ch_ctx, (uint8_t*) &be_buffer, 8))
931 : {
932 0 : goto cleanup;
933 : }
934 8 : if (BBS_OK != hash_to_scalar_update (cipher_suite,
935 : &ch_ctx,
936 : presentation_header,
937 : presentation_header_len))
938 : {
939 0 : goto cleanup;
940 : }
941 8 : if (BBS_OK != hash_to_scalar_finalize (cipher_suite,
942 : &ch_ctx,
943 : challenge,
944 8 : (uint8_t*) cipher_suite->challenge_dst,
945 8 : cipher_suite->challenge_dst_len))
946 : {
947 0 : goto cleanup;
948 : }
949 :
950 : // Serialize remainder of proof
951 8 : proof_ptr = proof + 3 * BBS_G1_ELEM_LEN;
952 : RLC_TRY {
953 : // Write out the challenge
954 8 : bn_write_bbs (proof + BBS_PROOF_LEN (undisclosed_indexes_len)
955 8 : - BBS_SCALAR_LEN, challenge);
956 :
957 : // e_hat
958 8 : bn_mul (e, e, challenge);
959 8 : bn_add (e_tilde, e_tilde, e);
960 8 : bn_mod (e_tilde, e_tilde, &(core_get ()->ep_r));
961 8 : bn_write_bbs (proof_ptr, e_tilde);
962 8 : proof_ptr += BBS_SCALAR_LEN;
963 :
964 : // r1_hat
965 8 : bn_mul (r1, r1, challenge);
966 8 : bn_mod (r1, r1, &(core_get ()->ep_r));
967 8 : bn_neg (r1, r1);
968 8 : bn_add (r1_tilde, r1_tilde, r1);
969 8 : bn_mod (r1_tilde, r1_tilde, &(core_get ()->ep_r)); // This works with negative r1_tilde
970 8 : bn_write_bbs (proof_ptr, r1_tilde);
971 8 : proof_ptr += BBS_SCALAR_LEN;
972 :
973 : // r3_hat (r2 contains r3)
974 8 : bn_mod_inv (r2, r2, &(core_get ()->ep_r));
975 8 : bn_mul (r2, r2, challenge);
976 8 : bn_mod (r2, r2, &(core_get ()->ep_r));
977 8 : bn_neg (r2, r2);
978 8 : bn_add (r3_tilde, r3_tilde, r2);
979 8 : bn_mod (r3_tilde, r3_tilde, &(core_get ()->ep_r)); // This works with negative r3_tilde
980 8 : bn_write_bbs (proof_ptr, r3_tilde);
981 8 : proof_ptr += BBS_SCALAR_LEN;
982 : }
983 : RLC_CATCH_ANY {
984 : goto cleanup;
985 : }
986 :
987 8 : for (undisclosed_indexes_idx = 0;
988 22 : undisclosed_indexes_idx < undisclosed_indexes_len;
989 14 : undisclosed_indexes_idx++)
990 : {
991 14 : if (BBS_OK != prf (cipher_suite, msg_scalar_tilde, 0, undisclosed_indexes_idx,
992 : prf_cookie))
993 : {
994 0 : goto cleanup;
995 : }
996 : RLC_TRY {
997 : // m_j_hat. We reuse the saved msg_scalar values
998 14 : bn_read_bbs (msg_scalar, proof_ptr);
999 14 : bn_mul (msg_scalar, msg_scalar, challenge);
1000 14 : bn_add (msg_scalar_tilde, msg_scalar_tilde, msg_scalar);
1001 14 : bn_mod (msg_scalar_tilde, msg_scalar_tilde, &(core_get ()->ep_r));
1002 14 : bn_write_bbs (proof_ptr, msg_scalar_tilde);
1003 14 : proof_ptr += BBS_SCALAR_LEN;
1004 : }
1005 : RLC_CATCH_ANY {
1006 : goto cleanup;
1007 : }
1008 : }
1009 :
1010 8 : res = BBS_OK;
1011 8 : cleanup:
1012 : bn_free (e);
1013 : bn_free (domain);
1014 : bn_free (msg_scalar);
1015 : bn_free (msg_scalar_tilde);
1016 : bn_free (r1);
1017 : bn_free (r2);
1018 : bn_free (e_tilde);
1019 : bn_free (r1_tilde);
1020 : bn_free (r3_tilde);
1021 : bn_free (challenge);
1022 : ep_free (A);
1023 : ep_free (B);
1024 : ep_free (Q_1);
1025 : ep_free (H_i);
1026 : ep_free (T1);
1027 : ep_free (T2);
1028 : ep_free (D);
1029 : ep_free (Abar);
1030 : ep_free (Bbar);
1031 8 : return res;
1032 : }
1033 :
1034 :
1035 : int
1036 14 : bbs_proof_prf (
1037 : bbs_cipher_suite_t *cipher_suite,
1038 : bn_t out,
1039 : uint8_t input_type,
1040 : uint64_t input,
1041 : void *seed
1042 : )
1043 : {
1044 : // All these have length 17
1045 : static uint8_t *dsts[] = {
1046 : (uint8_t*) "random msg scalar", (uint8_t*) "random r_1 scalar",
1047 : (uint8_t*) "random r_2 scalar", (uint8_t*) "random e_t scalar",
1048 : (uint8_t*) "random r1t scalar", (uint8_t*) "random r3t scalar",
1049 : };
1050 :
1051 14 : if (input_type >= LEN (dsts))
1052 0 : return BBS_ERROR;
1053 14 : return hash_to_scalar (cipher_suite,
1054 : out,
1055 14 : dsts[input_type],
1056 : 17,
1057 : 2,
1058 : seed,
1059 : (uint32_t) 32,
1060 : &input,
1061 : (uint32_t) 4);
1062 : }
1063 :
1064 :
1065 : int
1066 2 : bbs_proof_gen (
1067 : bbs_cipher_suite_t *cipher_suite,
1068 : const bbs_public_key pk,
1069 : const bbs_signature signature,
1070 : uint8_t *proof,
1071 : const uint8_t *header,
1072 : uint64_t header_len,
1073 : const uint8_t *presentation_header,
1074 : uint64_t presentation_header_len,
1075 : const uint64_t *disclosed_indexes,
1076 : uint64_t disclosed_indexes_len,
1077 : uint64_t num_messages,
1078 : ...
1079 : )
1080 : {
1081 : va_list ap;
1082 : uint8_t seed[32];
1083 2 : int ret = BBS_ERROR;
1084 :
1085 2 : va_start (ap, num_messages);
1086 :
1087 : RLC_TRY {
1088 : // Gather randomness. The seed is used for any randomness within this
1089 : // function. In particular, this implies that we do not need to store
1090 : // intermediate derivations. Currently, we derive new values via
1091 : // hash_to_scalar, but we might want to exchange that for
1092 : // something faster later on.
1093 2 : rand_bytes (seed, 32);
1094 : }
1095 : RLC_CATCH_ANY {
1096 : goto cleanup;
1097 : }
1098 :
1099 2 : if (BBS_OK != bbs_proof_gen_det (cipher_suite,
1100 : pk,
1101 : signature,
1102 : proof,
1103 : header,
1104 : header_len,
1105 : presentation_header,
1106 : presentation_header_len,
1107 : disclosed_indexes,
1108 : disclosed_indexes_len,
1109 : num_messages,
1110 : bbs_proof_prf,
1111 : seed,
1112 : ap))
1113 : {
1114 0 : goto cleanup;
1115 : }
1116 :
1117 2 : ret = BBS_OK;
1118 2 : cleanup:
1119 2 : va_end (ap);
1120 2 : return ret;
1121 : }
1122 :
1123 :
1124 : int
1125 8 : bbs_proof_verify (
1126 : bbs_cipher_suite_t *cipher_suite,
1127 : const bbs_public_key pk,
1128 : const uint8_t *proof,
1129 : uint64_t proof_len,
1130 : const uint8_t *header,
1131 : uint64_t header_len,
1132 : const uint8_t *presentation_header,
1133 : uint64_t presentation_header_len,
1134 : const uint64_t *disclosed_indexes,
1135 : uint64_t disclosed_indexes_len,
1136 : uint64_t num_messages,
1137 : ...
1138 : )
1139 : {
1140 : va_list ap;
1141 : uint8_t generator_ctx[48 + 8];
1142 : uint8_t T_buffer[2 * BBS_G1_ELEM_LEN];
1143 : uint8_t scalar_buffer[BBS_SCALAR_LEN];
1144 : const uint8_t *proof_ptr, *msg;
1145 : uint64_t msg_len, be_buffer;
1146 : bn_t domain, msg_scalar, e_hat, r1_hat, r3_hat, challenge,
1147 : challenge_prime;
1148 : ep_t Bv, Q_1, H_i, T1, T2, D, Abar, Bbar;
1149 : ep2_t W;
1150 : fp12_t paired1, paired2;
1151 8 : uint64_t disclosed_indexes_idx = 0;
1152 8 : uint64_t undisclosed_indexes_idx = 0;
1153 8 : uint64_t undisclosed_indexes_len = num_messages - disclosed_indexes_len;
1154 : union bbs_hash_context ch_ctx, dom_ctx;
1155 8 : int res = BBS_ERROR;
1156 :
1157 8 : va_start (ap, num_messages);
1158 :
1159 8 : if (! header)
1160 : {
1161 0 : header = (uint8_t*) "";
1162 0 : header_len = 0;
1163 : }
1164 :
1165 8 : if (! presentation_header)
1166 : {
1167 0 : presentation_header = (uint8_t*) "";
1168 0 : presentation_header_len = 0;
1169 : }
1170 :
1171 : bn_null (domain);
1172 : bn_null (msg_scalar);
1173 : bn_null (e_hat);
1174 : bn_null (r1_hat);
1175 : bn_null (r3_hat);
1176 : bn_null (challenge);
1177 : bn_null (challenge_prime);
1178 : ep_null (Bv);
1179 : ep_null (Q_1);
1180 : ep_null (H_i);
1181 : ep_null (T1);
1182 : ep_null (T2);
1183 : ep_null (D);
1184 : ep_null (Abar);
1185 : ep_null (Bbar);
1186 : ep2_null (W);
1187 : fp12_null (paired1);
1188 : fp12_null (paired2);
1189 :
1190 :
1191 : // Sanity check. We let the application give us the length explicitly,
1192 : // and perform the length check here.
1193 8 : if (proof_len != BBS_PROOF_LEN (undisclosed_indexes_len))
1194 : {
1195 0 : goto cleanup;
1196 : }
1197 :
1198 8 : if (BBS_OK != create_generator_init (cipher_suite,
1199 : generator_ctx,
1200 8 : (uint8_t*) cipher_suite->api_id,
1201 8 : cipher_suite->api_id_len))
1202 : {
1203 0 : goto cleanup;
1204 : }
1205 8 : if (BBS_OK != calculate_domain_init (cipher_suite, &dom_ctx, pk, num_messages))
1206 : {
1207 0 : goto cleanup;
1208 : }
1209 :
1210 : RLC_TRY {
1211 8 : bn_new (domain);
1212 8 : bn_new (msg_scalar);
1213 8 : bn_new (e_hat);
1214 8 : bn_new (r1_hat);
1215 8 : bn_new (r3_hat);
1216 8 : bn_new (challenge);
1217 8 : bn_new (challenge_prime);
1218 : ep_new (Bv);
1219 : ep_new (Q_1);
1220 : ep_new (H_i);
1221 : ep_new (T1);
1222 : ep_new (T2);
1223 : ep_new (D);
1224 : ep_new (Abar);
1225 : ep_new (Bbar);
1226 : ep2_new (W);
1227 : fp12_new (paired1);
1228 : fp12_new (paired2);
1229 :
1230 : // Parse pk
1231 8 : ep2_read_bbs (W, pk);
1232 :
1233 : // Parse the proof excluding the msg_scalar_hat values
1234 : // Those will be read later
1235 8 : proof_ptr = proof;
1236 8 : ep_read_bbs (Abar, proof_ptr);
1237 8 : proof_ptr += BBS_G1_ELEM_LEN;
1238 8 : ep_read_bbs (Bbar, proof_ptr);
1239 8 : proof_ptr += BBS_G1_ELEM_LEN;
1240 8 : ep_read_bbs (D, proof_ptr);
1241 8 : proof_ptr += BBS_G1_ELEM_LEN;
1242 8 : bn_read_bbs (e_hat, proof_ptr);
1243 8 : proof_ptr += BBS_SCALAR_LEN;
1244 8 : bn_read_bbs (r1_hat, proof_ptr);
1245 8 : proof_ptr += BBS_SCALAR_LEN;
1246 8 : bn_read_bbs (r3_hat, proof_ptr);
1247 8 : proof_ptr += BBS_SCALAR_LEN;
1248 8 : bn_read_bbs (challenge, proof + BBS_PROOF_LEN (undisclosed_indexes_len)
1249 8 : - BBS_SCALAR_LEN);
1250 :
1251 : // Calculate T1. We use T2 as a temporary variable here
1252 8 : ep_mul (T1, Bbar, challenge);
1253 8 : ep_mul (T2, Abar, e_hat);
1254 8 : ep_add (T1, T1, T2);
1255 8 : ep_mul (T2, D, r1_hat);
1256 8 : ep_add (T1, T1, T2);
1257 :
1258 : // Initialize Bv to P1 and T2 to D*r3_hat
1259 8 : ep_read_bbs (Bv, cipher_suite->p1);
1260 8 : ep_mul (T2, D, r3_hat);
1261 : }
1262 : RLC_CATCH_ANY {
1263 : goto cleanup;
1264 : }
1265 :
1266 : // Calculate Q_1
1267 8 : if (BBS_OK != create_generator_next (cipher_suite,
1268 : generator_ctx,
1269 : Q_1,
1270 8 : (uint8_t*) cipher_suite->api_id,
1271 8 : cipher_suite->api_id_len))
1272 : {
1273 0 : goto cleanup;
1274 : }
1275 8 : if (BBS_OK != calculate_domain_update (cipher_suite, &dom_ctx, Q_1))
1276 : {
1277 0 : goto cleanup;
1278 : }
1279 :
1280 : // Initialize challenge calculation
1281 8 : if (BBS_OK != hash_to_scalar_init (cipher_suite, &ch_ctx))
1282 : {
1283 0 : goto cleanup;
1284 : }
1285 8 : be_buffer = UINT64_H2BE (disclosed_indexes_len);
1286 8 : if (BBS_OK != hash_to_scalar_update (cipher_suite, &ch_ctx, (uint8_t*) &be_buffer, 8))
1287 : {
1288 0 : goto cleanup;
1289 : }
1290 :
1291 : // We loop over all messages. Disclosed messages are added to the
1292 : // challenge and accumulated onto Bv. Undisclosed messages have their
1293 : // blinded scalar values accumulated onto T2. Furthermore, we hash the
1294 : // generators for each index into the domain.
1295 54 : for (uint64_t i = 0; i<num_messages; i++)
1296 : {
1297 : // Calculate H_i
1298 46 : if (BBS_OK != create_generator_next (cipher_suite, generator_ctx, H_i,
1299 46 : (uint8_t*) cipher_suite->api_id,
1300 46 : cipher_suite->api_id_len)
1301 : )
1302 : {
1303 0 : goto cleanup;
1304 : }
1305 46 : if (BBS_OK != calculate_domain_update (cipher_suite, &dom_ctx, H_i))
1306 : {
1307 0 : goto cleanup;
1308 : }
1309 :
1310 46 : if (disclosed_indexes_idx < disclosed_indexes_len && disclosed_indexes[
1311 : disclosed_indexes_idx] == i)
1312 : {
1313 : // This message is disclosed.
1314 : // Read in the message and accumulate onto Bv
1315 32 : msg = va_arg (ap, uint8_t*);
1316 32 : msg_len = va_arg (ap, uint32_t);
1317 :
1318 : // Calculate msg_scalar (oneshot)
1319 32 : if (BBS_OK != hash_to_scalar (cipher_suite, msg_scalar,
1320 32 : (uint8_t*) cipher_suite->map_dst,
1321 32 : cipher_suite->map_dst_len, 1, msg,
1322 : (uint32_t) msg_len))
1323 : {
1324 0 : goto cleanup;
1325 : }
1326 : RLC_TRY {
1327 : // Update Bv.
1328 32 : ep_mul (H_i, H_i, msg_scalar);
1329 32 : ep_add (Bv, Bv, H_i);
1330 :
1331 : // Write out msg_scalar
1332 32 : bn_write_bbs (scalar_buffer, msg_scalar);
1333 : }
1334 : RLC_CATCH_ANY {
1335 : goto cleanup;
1336 : }
1337 : // Hash i and msg_scalar into the challenge
1338 32 : be_buffer = UINT64_H2BE (i);
1339 32 : if (BBS_OK != hash_to_scalar_update (cipher_suite, &ch_ctx,
1340 : (uint8_t*) &be_buffer, 8))
1341 : {
1342 0 : goto cleanup;
1343 : }
1344 32 : if (BBS_OK != hash_to_scalar_update (cipher_suite, &ch_ctx, scalar_buffer,
1345 : BBS_SCALAR_LEN))
1346 : {
1347 0 : goto cleanup;
1348 : }
1349 32 : disclosed_indexes_idx++;
1350 : }
1351 : else
1352 : {
1353 : // This message is undisclosed.
1354 : // Read a msg_scalar_hat value and accumulate it onto T2
1355 : RLC_TRY {
1356 : // Update T2.
1357 14 : bn_read_bbs (msg_scalar, proof_ptr);
1358 14 : proof_ptr += BBS_SCALAR_LEN;
1359 14 : ep_mul (H_i, H_i, msg_scalar);
1360 14 : ep_add (T2, T2, H_i);
1361 : }
1362 : RLC_CATCH_ANY {
1363 : goto cleanup;
1364 : }
1365 14 : undisclosed_indexes_idx++;
1366 : }
1367 : }
1368 :
1369 : // Sanity check. If any indices for disclosed messages were out of order
1370 : // or invalid, we fail here.
1371 8 : if (disclosed_indexes_idx != disclosed_indexes_len)
1372 : {
1373 0 : goto cleanup;
1374 : }
1375 :
1376 : // Finalize domain calculation
1377 8 : if (BBS_OK != calculate_domain_finalize (cipher_suite,
1378 : &dom_ctx,
1379 : domain,
1380 : header,
1381 : header_len,
1382 8 : (uint8_t*) cipher_suite->api_id,
1383 8 : cipher_suite->api_id_len))
1384 : {
1385 0 : goto cleanup;
1386 : }
1387 : RLC_TRY {
1388 : // Finalize Bv
1389 8 : ep_mul (Q_1, Q_1, domain);
1390 8 : ep_add (Bv, Bv, Q_1);
1391 :
1392 : // Finalize T2
1393 8 : ep_mul (Bv, Bv, challenge);
1394 8 : ep_add (T2, T2, Bv);
1395 :
1396 : // Write out T1 and T2 for the challenge
1397 8 : ep_write_bbs (T_buffer, T1);
1398 8 : ep_write_bbs (T_buffer + BBS_G1_ELEM_LEN, T2);
1399 :
1400 : // Write out the domain. We reuse scalar_buffer
1401 8 : bn_write_bbs (scalar_buffer, domain);
1402 : }
1403 : RLC_CATCH_ANY {
1404 : goto cleanup;
1405 : }
1406 :
1407 : // Finish calculating the challenge
1408 8 : if (BBS_OK != hash_to_scalar_update (cipher_suite, &ch_ctx, proof, 3 * BBS_G1_ELEM_LEN))
1409 : {
1410 0 : goto cleanup;
1411 : }
1412 8 : if (BBS_OK != hash_to_scalar_update (cipher_suite, &ch_ctx, T_buffer, 2 * BBS_G1_ELEM_LEN))
1413 : {
1414 0 : goto cleanup;
1415 : }
1416 8 : if (BBS_OK != hash_to_scalar_update (cipher_suite, &ch_ctx, scalar_buffer, BBS_SCALAR_LEN))
1417 : {
1418 0 : goto cleanup;
1419 : }
1420 8 : be_buffer = UINT64_H2BE (presentation_header_len);
1421 8 : if (BBS_OK != hash_to_scalar_update (cipher_suite, &ch_ctx, (uint8_t*) &be_buffer, 8))
1422 : {
1423 0 : goto cleanup;
1424 : }
1425 8 : if (BBS_OK != hash_to_scalar_update (cipher_suite,
1426 : &ch_ctx,
1427 : presentation_header,
1428 : presentation_header_len))
1429 : {
1430 0 : goto cleanup;
1431 : }
1432 8 : if (BBS_OK != hash_to_scalar_finalize (cipher_suite,
1433 : &ch_ctx,
1434 : challenge_prime,
1435 8 : (uint8_t*) cipher_suite->challenge_dst,
1436 8 : cipher_suite->challenge_dst_len))
1437 : {
1438 0 : goto cleanup;
1439 : }
1440 :
1441 : // Verification Step 1: The PoK was valid
1442 8 : if (RLC_EQ != bn_cmp (challenge, challenge_prime))
1443 : {
1444 0 : goto cleanup;
1445 : }
1446 :
1447 : // Verification Step 2: The original signature was valid
1448 : RLC_TRY {
1449 : // Compute pairings e(Abar, W) * e(Bbar, -BP2)
1450 : // For valid signatures, this is the identity.
1451 8 : pp_map_oatep_k12 (paired1, Abar, W);
1452 :
1453 8 : ep2_curve_get_gen (W); // Reuse W
1454 8 : ep2_neg (W, W);
1455 8 : pp_map_oatep_k12 (paired2, Bbar, W);
1456 :
1457 8 : fp12_mul (paired1, paired1, paired2);
1458 : }
1459 : RLC_CATCH_ANY {
1460 : goto cleanup;
1461 : }
1462 :
1463 : // Check signature equation
1464 8 : if (RLC_EQ != fp12_cmp_dig (paired1, 1))
1465 : {
1466 0 : goto cleanup;
1467 : }
1468 :
1469 8 : res = BBS_OK;
1470 8 : cleanup:
1471 : bn_free (domain);
1472 : bn_free (msg_scalar);
1473 : bn_free (e_hat);
1474 : bn_free (r1_hat);
1475 : bn_free (r3_hat);
1476 : bn_free (challenge);
1477 : bn_free (challenge_prime);
1478 : ep_free (Bv);
1479 : ep_free (Q_1);
1480 : ep_free (H_i);
1481 : ep_free (T1);
1482 : ep_free (T2);
1483 : ep_free (D);
1484 : ep_free (Abar);
1485 : ep_free (Bbar);
1486 : ep2_free (W);
1487 : fp12_free (paired1);
1488 : fp12_free (paired2);
1489 8 : va_end (ap);
1490 8 : return res;
1491 : }
|