LCOV - code coverage report
Current view: top level - src - bbs.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 80.4 % 480 386
Test Date: 2025-06-13 08:12:24 Functions: 90.9 % 11 10

            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              : }
        

Generated by: LCOV version 2.0-1