github.com/onflow/flow-go/crypto@v0.24.8/bls12381_utils.c (about)

     1  // +build relic
     2  
     3  // this file contains utility functions for the curve BLS 12-381
     4  // these tools are shared by the BLS signature scheme, the BLS based threshold signature
     5  // and the BLS distributed key generation protocols
     6  
     7  #include "bls12381_utils.h"
     8  #include "bls_include.h"
     9  #include "assert.h"
    10  
    11  // The functions are tested for ALLOC=AUTO (not for ALLOC=DYNAMIC)
    12  
    13  // return macro values to the upper Go Layer
    14  int get_valid() {
    15      return VALID;
    16  }
    17  
    18  int get_invalid() {
    19      return INVALID;
    20  }
    21  
    22  void bn_new_wrapper(bn_t a) {
    23      bn_new(a);
    24  }
    25  
    26  // global variable of the pre-computed data
    27  prec_st bls_prec_st;
    28  prec_st* bls_prec = NULL;
    29  
    30  // required constants for the optimized SWU hash to curve
    31  #if (hashToPoint == LOCAL_SSWU)
    32  extern const uint64_t iso_Nx_data[ELLP_Nx_LEN][Fp_DIGITS];
    33  extern const uint64_t iso_Ny_data[ELLP_Ny_LEN][Fp_DIGITS];
    34  #endif
    35  
    36  #if (MEMBERSHIP_CHECK_G1 == BOWE)
    37  extern const uint64_t beta_data[Fp_DIGITS];
    38  extern const uint64_t z2_1_by3_data[2];
    39  #endif
    40  
    41  // sets the global variable to input
    42  void precomputed_data_set(const prec_st* p) {
    43      bls_prec = (prec_st*)p;
    44  }
    45  
    46  // Reads a prime field element from a digit vector in big endian format.
    47  // There is no conversion to Montgomery domain in this function.
    48   #define fp_read_raw(a, data_pointer) dv_copy((a), (data_pointer), Fp_DIGITS)
    49  
    50  // pre-compute some data required for curve BLS12-381
    51  prec_st* init_precomputed_data_BLS12_381() {
    52      bls_prec = &bls_prec_st;
    53      ctx_t* ctx = core_get();
    54  
    55      // (p-1)/2
    56      bn_div_dig(&bls_prec->p_1div2, &ctx->prime, 2);
    57      #if (hashToPoint == LOCAL_SSWU)
    58      // (p-3)/4
    59      bn_div_dig(&bls_prec->p_3div4, &bls_prec->p_1div2, 2);
    60      // sqrt(-z)
    61      fp_neg(bls_prec->sqrt_z, ctx->ep_map_u);
    62      fp_srt(bls_prec->sqrt_z, bls_prec->sqrt_z);
    63      // -a1 and a1*z
    64      fp_neg(bls_prec->minus_a1, ctx->ep_iso.a);
    65      fp_mul(bls_prec->a1z, ctx->ep_iso.a, ctx->ep_map_u);
    66      
    67      for (int i=0; i<ELLP_Nx_LEN; i++)  
    68          fp_read_raw(bls_prec->iso_Nx[i], iso_Nx_data[i]);
    69      for (int i=0; i<ELLP_Ny_LEN; i++)  
    70          fp_read_raw(bls_prec->iso_Ny[i], iso_Ny_data[i]);
    71      #endif
    72  
    73      #if (MEMBERSHIP_CHECK_G1 == BOWE)
    74      bn_new(&bls_prec->beta);
    75      bn_read_raw(&bls_prec->beta, beta_data, Fp_DIGITS);
    76      bn_new(&bls_prec->z2_1_by3);
    77      bn_read_raw(&bls_prec->z2_1_by3, z2_1_by3_data, 2);
    78      #endif
    79  
    80      // Montgomery constant R
    81      fp_set_dig(bls_prec->r, 1);
    82      return bls_prec;
    83  }
    84  
    85  // Initializes Relic context with BLS12-381 parameters
    86  ctx_t* relic_init_BLS12_381() { 
    87      // check Relic was compiled with the right conf 
    88      assert(ALLOC == AUTO);
    89  
    90      // sanity check of Relic constants the package is relying on
    91      assert(RLC_OK == RLC_EQ);
    92  
    93      // initialize relic core with a new context
    94      ctx_t* bls_ctx = (ctx_t*) calloc(1, sizeof(ctx_t));
    95      if (!bls_ctx) return NULL;
    96      core_set(bls_ctx);
    97      if (core_init() != RLC_OK) return NULL;
    98  
    99      // init BLS curve
   100      int ret = RLC_OK;
   101      #if (FP_PRIME == 381)
   102      ret = ep_param_set_any_pairf(); // sets B12_P381 if FP_PRIME = 381 in relic config
   103      #else
   104      ep_param_set(B12_P381);
   105      ep2_curve_set_twist(EP_MTYPE);  // Multiplicative twist 
   106      #endif 
   107  
   108      if (ret != RLC_OK) return NULL;
   109      return core_get();
   110  }
   111  
   112  // seeds relic PRG
   113  void seed_relic(byte* seed, int len) {
   114      #if RAND == HASHD
   115      // instantiate a new DRBG
   116      ctx_t *ctx = core_get();
   117      ctx->seeded = 0;
   118      #endif
   119      rand_seed(seed, len);
   120  }
   121  
   122  // Exponentiation of a generic point p in G1
   123  void ep_mult(ep_t res, const ep_t p, const bn_t expo) {
   124      // Using window NAF of size 2 
   125      ep_mul_lwnaf(res, p, expo);
   126  }
   127  
   128  // Exponentiation of generator g1 in G1
   129  // These two function are here for bench purposes only
   130  void ep_mult_gen_bench(ep_t res, const bn_t expo) {
   131      // Using precomputed table of size 4
   132      ep_mul_gen(res, (bn_st *)expo);
   133  }
   134  
   135  void ep_mult_generic_bench(ep_t res, const bn_t expo) {
   136      // generic point multiplication
   137      ep_mult(res, &core_get()->ep_g, expo);
   138  }
   139  
   140  // Exponentiation of a generic point p in G2
   141  void ep2_mult(ep2_t res, ep2_t p, bn_t expo) {
   142      // Using window NAF of size 2
   143      ep2_mul_lwnaf(res, p, expo);
   144  }
   145  
   146  // Exponentiation of fixed g2 in G2
   147  void ep2_mult_gen(ep2_t res, const bn_t expo) {
   148      // Using precomputed table of size 4
   149      g2_mul_gen(res, (bn_st*)expo);
   150  }
   151  
   152  // DEBUG printing functions 
   153  void bytes_print_(char* s, byte* data, int len) {
   154      printf("[%s]:\n", s);
   155      for (int i=0; i<len; i++) 
   156          printf("%02x,", data[i]);
   157      printf("\n");
   158  }
   159  
   160  // DEBUG printing functions 
   161  void fp_print_(char* s, fp_st a) {
   162      char* str = malloc(sizeof(char) * fp_size_str(a, 16));
   163      fp_write_str(str, 100, a, 16);
   164      printf("[%s]:\n%s\n", s, str);
   165      free(str);
   166  }
   167  
   168  void bn_print_(char* s, bn_st *a) {
   169      char* str = malloc(sizeof(char) * bn_size_str(a, 16));
   170      bn_write_str(str, 128, a, 16);
   171      printf("[%s]:\n%s\n", s, str);
   172      free(str);
   173  }
   174  
   175  void ep_print_(char* s, ep_st* p) {
   176      printf("[%s]:\n", s);
   177      g1_print(p);
   178  }
   179  
   180  void ep2_print_(char* s, ep2_st* p) {
   181      printf("[%s]:\n", s);
   182      g2_print(p);
   183  }
   184  
   185  // generates a random number less than the order r
   186  void bn_randZr_star(bn_t x) {
   187      // reduce the modular reduction bias
   188      const int seed_len = BITS_TO_BYTES(Fr_BITS + SEC_BITS);
   189      byte seed[seed_len];
   190      rand_bytes(seed, seed_len);
   191      bn_map_to_Zr_star(x, seed, seed_len);
   192      rand_bytes(seed, seed_len); // overwrite seed
   193  }
   194  
   195  // generates a random number less than the order r
   196  void bn_randZr(bn_t x) {
   197      // reduce the modular reduction bias
   198      bn_new_size(x, BITS_TO_DIGITS(Fr_BITS + SEC_BITS));
   199      bn_rand(x, RLC_POS, Fr_BITS + SEC_BITS);
   200      bn_mod(x, x, &core_get()->ep_r);
   201  }
   202  
   203  // Reads a scalar from an array and maps it to Zr.
   204  // The resulting scalar `a` satisfies 0 <= a < r.
   205  // `len` must be less than BITS_TO_BYTES(RLC_BN_BITS).
   206  // It returns VALID if scalar is zero and INVALID otherwise
   207  int bn_map_to_Zr(bn_t a, const uint8_t* bin, int len) {
   208      bn_t tmp;
   209      bn_new(tmp);
   210      bn_new_size(tmp, BYTES_TO_DIGITS(len));
   211      bn_read_bin(tmp, bin, len);
   212      bn_mod(a, tmp, &core_get()->ep_r);
   213      bn_rand(tmp, RLC_POS, len << 3); // overwrite tmp
   214      bn_free(tmp);
   215      if (bn_cmp_dig(a, 0) == RLC_EQ) {
   216          return VALID;
   217      }
   218      return INVALID;
   219  }
   220  
   221  // Reads a scalar from an array and maps it to Zr*.
   222  // The resulting scalar `a` satisfies 0 < a < r.
   223  // `len` must be less than BITS_TO_BYTES(RLC_BN_BITS)
   224  void bn_map_to_Zr_star(bn_t a, const uint8_t* bin, int len) {
   225      bn_t tmp;
   226      bn_new(tmp);
   227      bn_new_size(tmp, BYTES_TO_DIGITS(len));
   228      bn_read_bin(tmp, bin, len);
   229      bn_t r_1;
   230      bn_new(r_1); 
   231      bn_sub_dig(r_1, &core_get()->ep_r, 1);
   232      bn_mod_basic(a,tmp,r_1);
   233      bn_add_dig(a,a,1);
   234      bn_rand(tmp, RLC_POS, len << 3); // overwrite tmp
   235      bn_free(tmp);
   236      bn_free(r_1);
   237  }
   238  
   239  // returns the sign of y.
   240  // 1 if y > (p - 1)/2 and 0 otherwise.
   241  static int fp_get_sign(const fp_t y) {
   242      bn_t bn_y;
   243      bn_new(bn_y);
   244      fp_prime_back(bn_y, y);
   245      return bn_cmp(bn_y, &bls_prec->p_1div2) == RLC_GT;		
   246  }
   247  
   248  // ep_write_bin_compact exports a point a in E(Fp) to a buffer bin in a compressed or uncompressed form.
   249  // len is the allocated size of the buffer bin.
   250  // The serialization is following:
   251  // https://www.ietf.org/archive/id/draft-irtf-cfrg-pairing-friendly-curves-08.html#name-zcash-serialization-format-) 
   252  // The code is a modified version of Relic ep_write_bin
   253  void ep_write_bin_compact(byte *bin, const ep_t a, const int len) {
   254      const int G1_size = (G1_BYTES/(G1_SERIALIZATION+1));
   255  
   256      if (len!=G1_size) {
   257          RLC_THROW(ERR_NO_BUFFER);
   258          return;
   259      }
   260   
   261      if (ep_is_infty(a)) {
   262              // set the infinity bit
   263              bin[0] = (G1_SERIALIZATION << 7) | 0x40;
   264              memset(bin+1, 0, G1_size-1);
   265              return;
   266      }
   267  
   268      RLC_TRY {
   269          ep_t t;
   270          ep_null(t);
   271          ep_new(t); 
   272          ep_norm(t, a);
   273          fp_write_bin(bin, Fp_BYTES, t->x);
   274  
   275          if (G1_SERIALIZATION == COMPRESSED) {
   276              bin[0] |= (fp_get_sign(t->y) << 5);
   277          } else {
   278              fp_write_bin(bin + Fp_BYTES, Fp_BYTES, t->y);
   279          }
   280          ep_free(t);
   281      } RLC_CATCH_ANY {
   282          RLC_THROW(ERR_CAUGHT);
   283      }
   284  
   285      bin[0] |= (G1_SERIALIZATION << 7);
   286   }
   287  
   288  // fp_read_bin_safe is a modified version of Relic's (void fp_read_bin).
   289  // It reads a field element from a buffer and makes sure the big number read can be 
   290  // written as a field element (is reduced modulo p). 
   291  // Unlike Relic's versions, the function does not reduce the read integer modulo p and does
   292  // not throw an exception for an integer larger than p. The function returns RLC_OK if the input
   293  // corresponds to a field element, and returns RLC_ERR otherwise. 
   294  static int fp_read_bin_safe(fp_t a, const uint8_t *bin, int len) {
   295      if (len != Fp_BYTES) {
   296          return RLC_ERR;
   297      }
   298  
   299      int ret = RLC_ERR; 
   300      bn_t t;
   301      bn_new(t);
   302      bn_read_bin(t, bin, Fp_BYTES);
   303  
   304      // make sure read bn is reduced modulo p
   305      // first check is sanity check, since current implementation of `bn_read_bin` insures
   306      // output bn is positive
   307      if (bn_sign(t) == RLC_NEG || bn_cmp(t, &core_get()->prime) != RLC_LT) {
   308          goto out;
   309      } 
   310  
   311      if (bn_is_zero(t)) {
   312          fp_zero(a);
   313      } else {
   314          if (t->used == 1) {
   315              fp_prime_conv_dig(a, t->dp[0]);
   316          } else {
   317              fp_prime_conv(a, t);
   318          }
   319      }	
   320      ret = RLC_OK;
   321  out:
   322      bn_free(t);
   323      return ret;
   324  }
   325  
   326  // ep_read_bin_compact imports a point from a buffer in a compressed or uncompressed form.
   327  // len is the size of the input buffer.
   328  //
   329  // The resulting point is guaranteed to be on the curve E1.
   330  // The serialization follows:
   331  // https://www.ietf.org/archive/id/draft-irtf-cfrg-pairing-friendly-curves-08.html#name-zcash-serialization-format-) 
   332  // The code is a modified version of Relic ep_read_bin
   333  //
   334  // It returns RLC_OK if the inputs are valid (input buffer lengths are valid and coordinates correspond
   335  // to a point on curve) and the execution completes, and RLC_ERR otherwise.
   336  int ep_read_bin_compact(ep_t a, const byte *bin, const int len) {
   337      // check the length
   338      const int G1_size = (G1_BYTES/(G1_SERIALIZATION+1));
   339      if (len!=G1_size) {
   340          return RLC_ERR;
   341      }
   342  
   343      // check the compression bit
   344      int compressed = bin[0] >> 7;
   345      if ((compressed == 1) != (G1_SERIALIZATION == COMPRESSED)) {
   346          return RLC_ERR;
   347      } 
   348  
   349      // check if the point is infinity
   350      int is_infinity = bin[0] & 0x40;
   351      if (is_infinity) {
   352          // check if the remaining bits are cleared
   353          if (bin[0] & 0x3F) {
   354              return RLC_ERR;
   355          }
   356          for (int i=1; i<G1_size-1; i++) {
   357              if (bin[i]) {
   358                  return RLC_ERR;
   359              } 
   360          }
   361  		ep_set_infty(a);
   362  		return RLC_OK;
   363  	} 
   364  
   365      // read the sign bit and check for consistency
   366      int y_sign = (bin[0] >> 5) & 1;
   367      if (y_sign && (!compressed)) {
   368          return RLC_ERR;
   369      } 
   370  
   371  	a->coord = BASIC;
   372  	fp_set_dig(a->z, 1);
   373      // use a temporary buffer to mask the header bits and read a.x 
   374      byte temp[Fp_BYTES];
   375      memcpy(temp, bin, Fp_BYTES);
   376      temp[0] &= 0x1F;
   377      if (fp_read_bin_safe(a->x, temp, sizeof(temp)) != RLC_OK) {
   378          return RLC_ERR;
   379      }
   380  
   381      if (G1_SERIALIZATION == UNCOMPRESSED) { 
   382          if (fp_read_bin_safe(a->y, bin + Fp_BYTES, Fp_BYTES) != RLC_OK) {
   383              return RLC_ERR;
   384          }
   385          // check read point is on curve
   386          if (!ep_on_curve(a)) {
   387              return RLC_ERR;
   388          }
   389          return RLC_OK;
   390      }
   391      fp_zero(a->y);
   392      fp_set_bit(a->y, 0, y_sign);
   393      if (ep_upk(a, a) == 1) {
   394          // resulting point is guaranteed to be on curve
   395          return RLC_OK;
   396      }
   397      return RLC_ERR;
   398  }
   399  
   400  
   401  // returns the sign of y.
   402  // sign(y_0) if y_1 = 0, else sign(y_1)
   403  static int fp2_get_sign(fp2_t y) {
   404      if (fp_is_zero(y[1])) { // no need to convert back as the montgomery form of 0 is 0
   405          return fp_get_sign(y[0]);
   406      }
   407      return fp_get_sign(y[1]);
   408  }
   409  
   410  // ep2_write_bin_compact exports a point in E(Fp^2) to a buffer in a compressed or uncompressed form.
   411  // len is the allocated size of the buffer bin.
   412  // The serialization is following:
   413  // https://www.ietf.org/archive/id/draft-irtf-cfrg-pairing-friendly-curves-08.html#name-zcash-serialization-format-)
   414  // The code is a modified version of Relic ep2_write_bin 
   415  void ep2_write_bin_compact(byte *bin, const ep2_t a, const int len) {
   416      ep2_t t;
   417      ep2_null(t);
   418      const int G2_size = (G2_BYTES/(G2_SERIALIZATION+1));
   419  
   420      if (len!=G2_size) {
   421          RLC_THROW(ERR_NO_BUFFER);
   422          return;
   423      }
   424   
   425      if (ep2_is_infty((ep2_st *)a)) {
   426              // set the infinity bit
   427              bin[0] = (G2_SERIALIZATION << 7) | 0x40;
   428              memset(bin+1, 0, G2_size-1);
   429              return;
   430      }
   431  
   432      RLC_TRY {
   433          ep2_new(t);
   434          ep2_norm(t, (ep2_st *)a);
   435          fp2_write_bin(bin, Fp2_BYTES, t->x, 0);
   436  
   437          if (G2_SERIALIZATION == COMPRESSED) {
   438              bin[0] |= (fp2_get_sign(t->y) << 5);
   439          } else {
   440              fp2_write_bin(bin + Fp2_BYTES, Fp2_BYTES, t->y, 0);
   441          }
   442      } RLC_CATCH_ANY {
   443          RLC_THROW(ERR_CAUGHT);
   444      }
   445  
   446      bin[0] |= (G2_SERIALIZATION << 7);
   447      ep_free(t);
   448  }
   449  
   450  // fp2_read_bin_safe is a modified version of Relic's (void fp2_read_bin).
   451  // It reads an Fp^2 element from a buffer and makes sure the big numbers read can be 
   452  // written as field elements (are reduced modulo p). 
   453  // Unlike Relic's versions, the function does not reduce the read integers modulo p and does
   454  // not throw an exception for integers larger than p. The function returns RLC_OK if the input
   455  // corresponds to a field element in Fp^2, and returns RLC_ERR otherwise.
   456  static int fp2_read_bin_safe(fp2_t a, const uint8_t *bin, int len) {
   457      if (len != Fp2_BYTES) {
   458          return RLC_ERR;
   459      }
   460      if (fp_read_bin_safe(a[0], bin, Fp_BYTES) != RLC_OK) {
   461          return RLC_ERR;
   462      }
   463      if (fp_read_bin_safe(a[1], bin + Fp_BYTES, Fp_BYTES) != RLC_OK) {
   464          return RLC_ERR;
   465      }
   466      return RLC_OK;
   467  }
   468  
   469  // ep2_read_bin_compact imports a point from a buffer in a compressed or uncompressed form.
   470  // The resulting point is guaranteed to be on curve E2.
   471  //
   472  // It returns RLC_OK if the inputs are valid (input buffer lengths are valid and read coordinates
   473  // correspond to a point on curve) and the execution completes and RLC_ERR otherwise.
   474  // The code is a modified version of Relic ep2_read_bin
   475  int ep2_read_bin_compact(ep2_t a, const byte *bin, const int len) {
   476      // check the length
   477      const int G2size = (G2_BYTES/(G2_SERIALIZATION+1));
   478      if (len!=G2size) {
   479          return RLC_ERR;
   480      }
   481  
   482      // check the compression bit
   483      int compressed = bin[0] >> 7;
   484      if ((compressed == 1) != (G2_SERIALIZATION == COMPRESSED)) {
   485          return RLC_ERR;
   486      } 
   487  
   488      // check if the point in infinity
   489      int is_infinity = bin[0] & 0x40;
   490      if (is_infinity) {
   491          // the remaining bits need to be cleared
   492          if (bin[0] & 0x3F) {
   493              return RLC_ERR;
   494          }
   495          for (int i=1; i<G2size-1; i++) {
   496              if (bin[i]) {
   497                  return RLC_ERR;
   498              } 
   499          }
   500  		ep2_set_infty(a);
   501  		return RLC_OK;
   502  	} 
   503  
   504      // read the sign bit and check for consistency
   505      int y_sign = (bin[0] >> 5) & 1;
   506      if (y_sign && (!compressed)) {
   507          return RLC_ERR;
   508      } 
   509      
   510  	a->coord = BASIC;
   511      fp2_set_dig(a->z, 1);   // a.z
   512      // use a temporary buffer to mask the header bits and read a.x
   513      byte temp[Fp2_BYTES];
   514      memcpy(temp, bin, Fp2_BYTES);
   515      temp[0] &= 0x1F;        // clear the header bits
   516      if (fp2_read_bin_safe(a->x, temp, sizeof(temp)) != RLC_OK) {
   517          return RLC_ERR;
   518      }
   519  
   520      if (G2_SERIALIZATION == UNCOMPRESSED) {
   521          if (fp2_read_bin_safe(a->y, bin + Fp2_BYTES, Fp2_BYTES) != RLC_OK){ 
   522              return RLC_ERR;
   523          }
   524          // check read point is on curve
   525          if (!ep2_on_curve(a)) {
   526              return RLC_ERR;
   527          }
   528          return RLC_OK;
   529      }
   530      
   531      fp2_zero(a->y);
   532      fp_set_bit(a->y[0], 0, y_sign);
   533      fp_zero(a->y[1]);
   534      if (ep2_upk(a, a) == 1) {
   535          // resulting point is guaranteed to be on curve
   536          return RLC_OK;
   537      }
   538      return RLC_ERR;
   539  }
   540  
   541  // reads a scalar in a and checks it is a valid Zr element (a < r)
   542  // returns RLC_OK if the scalar is valid and RLC_ERR otherwise.
   543  int bn_read_Zr_bin(bn_t a, const uint8_t *bin, int len) {
   544      if (len!=Fr_BYTES) {
   545          return RLC_ERR;
   546      }
   547      bn_read_bin(a, bin, Fr_BYTES);
   548      bn_t r;
   549      bn_new(r); 
   550      g2_get_ord(r);
   551      if (bn_cmp(a, r) == RLC_LT) {
   552          return RLC_OK;
   553      }
   554      return RLC_ERR;
   555  }
   556  
   557  // computes the sum of the array elements x and writes the sum in jointx
   558  // the sum is computed in Zr
   559  void bn_sum_vector(bn_t jointx, const bn_st* x, const int len) {
   560      bn_t r;
   561      bn_new(r); 
   562      g2_get_ord(r);
   563      bn_set_dig(jointx, 0);
   564      bn_new_size(jointx, BITS_TO_DIGITS(Fr_BITS+1));
   565      for (int i=0; i<len; i++) {
   566          bn_add(jointx, jointx, &x[i]);
   567          if (bn_cmp(jointx, r) == RLC_GT) 
   568              bn_sub(jointx, jointx, r);
   569      }
   570      bn_free(r);
   571  }
   572  
   573  // computes the sum of the G2 array elements y and writes the sum in jointy
   574  void ep2_sum_vector(ep2_t jointy, ep2_st* y, const int len){
   575      ep2_set_infty(jointy);
   576      for (int i=0; i<len; i++){
   577          ep2_add_projc(jointy, jointy, &y[i]);
   578      }
   579      ep2_norm(jointy, jointy); // not necessary but left here to optimize the 
   580                              // multiple pairing computations with the same 
   581                              // public key
   582  }
   583  
   584  // Verifies the validity of 2 SPoCK proofs and 2 public keys.
   585  // Membership check in G1 of both proofs is verified in this function.
   586  // Membership check in G2 of both keys is not verified in this function.
   587  // the membership check in G2 is separated to allow optimizing multiple verifications 
   588  // using the same public keys.
   589  int bls_spock_verify(const ep2_t pk1, const byte* sig1, const ep2_t pk2, const byte* sig2) {  
   590      ep_t elemsG1[2];
   591      ep2_t elemsG2[2];
   592  
   593      // elemsG1[0] = s1
   594      ep_new(elemsG1[0]);
   595      int read_ret = ep_read_bin_compact(elemsG1[0], sig1, SIGNATURE_LEN);
   596      if (read_ret != RLC_OK) 
   597          return read_ret;
   598  
   599      // check s1 is in G1
   600      if (check_membership_G1(elemsG1[0]) != VALID) // only enabled if MEMBERSHIP_CHECK==1
   601          return INVALID;
   602  
   603      // elemsG1[1] = s2
   604      ep_new(elemsG1[1]);
   605      read_ret = ep_read_bin_compact(elemsG1[1], sig2, SIGNATURE_LEN);
   606      if (read_ret != RLC_OK) 
   607          return read_ret;
   608  
   609      // check s2 in G1
   610      if (check_membership_G1(elemsG1[1]) != VALID) // only enabled if MEMBERSHIP_CHECK==1
   611          return INVALID; 
   612  
   613      // elemsG2[1] = pk1
   614      ep2_new(elemsG2[1]);
   615      ep2_copy(elemsG2[1], (ep2_st*)pk1);
   616  
   617      // elemsG2[0] = pk2
   618      ep2_new(elemsG2[0]);
   619      ep2_copy(elemsG2[0], (ep2_st*)pk2);
   620  
   621  #if DOUBLE_PAIRING  
   622      // elemsG2[0] = -pk2
   623      ep2_neg(elemsG2[0], elemsG2[0]);
   624  
   625      fp12_t pair;
   626      fp12_new(&pair);
   627      // double pairing with Optimal Ate 
   628      pp_map_sim_oatep_k12(pair, (ep_t*)(elemsG1) , (ep2_t*)(elemsG2), 2);
   629  
   630      // compare the result to 1
   631      int res = fp12_cmp_dig(pair, 1);
   632  
   633  #elif SINGLE_PAIRING   
   634      fp12_t pair1, pair2;
   635      fp12_new(&pair1); fp12_new(&pair2);
   636      pp_map_oatep_k12(pair1, elemsG1[0], elemsG2[0]);
   637      pp_map_oatep_k12(pair2, elemsG1[1], elemsG2[1]);
   638  
   639      int res = fp12_cmp(pair1, pair2);
   640  #endif
   641      fp12_free(&one);
   642      ep_free(elemsG1[0]);
   643      ep_free(elemsG1[1]);
   644      ep2_free(elemsG2[0]);
   645      ep2_free(elemsG2[1]);
   646      
   647      if (core_get()->code == RLC_OK) {
   648          if (res == RLC_EQ) return VALID;
   649          return INVALID;
   650      }
   651      return UNDEFINED;
   652  }
   653  
   654  // Subtracts the sum of a G2 array elements y from an element x and writes the 
   655  // result in res
   656  void ep2_subtract_vector(ep2_t res, ep2_t x, ep2_st* y, const int len){
   657      ep2_sum_vector(res, y, len);
   658      ep2_neg(res, res);
   659      ep2_add_projc(res, x, res);
   660  }
   661  
   662  // computes the sum of the G1 array elements y and writes the sum in jointy
   663  void ep_sum_vector(ep_t jointx, ep_st* x, const int len) {
   664      ep_set_infty(jointx);
   665      for (int i=0; i<len; i++){
   666          ep_add_jacob(jointx, jointx, &x[i]);
   667      }
   668  }
   669  
   670  // Computes the sum of the signatures (G1 elements) flattened in a single sigs array
   671  // and writes the sum (G1 element) as bytes in dest.
   672  // The function assumes sigs is correctly allocated with regards to len.
   673  int ep_sum_vector_byte(byte* dest, const byte* sigs_bytes, const int len) {
   674      int error = UNDEFINED;
   675  
   676      // temp variables
   677      ep_t acc;        
   678      ep_new(acc);
   679      ep_set_infty(acc);
   680      ep_st* sigs = (ep_st*) malloc(len * sizeof(ep_st));
   681      if (!sigs) goto mem_error;
   682      for (int i=0; i < len; i++) ep_new(sigs[i]);
   683  
   684      // import the points from the array
   685      for (int i=0; i < len; i++) {
   686          // deserialize each point from the input array
   687          error = ep_read_bin_compact(&sigs[i], &sigs_bytes[SIGNATURE_LEN*i], SIGNATURE_LEN);
   688          if (error != RLC_OK) {
   689              goto out;
   690          }
   691      }
   692      // sum the points
   693      ep_sum_vector(acc, sigs, len);
   694      // export the result
   695      ep_write_bin_compact(dest, acc, SIGNATURE_LEN);
   696  
   697      error = VALID;
   698  out:
   699      // free the temp memory
   700      ep_free(acc);
   701      for (int i=0; i < len; i++) ep_free(sigs[i]);
   702      free(sigs);
   703  mem_error:
   704      return error;
   705  }
   706  
   707  // uses a simple scalar multiplication by G1's order
   708  // to check whether a point on the curve E1 is in G1.
   709  int simple_subgroup_check_G1(const ep_t p){
   710      ep_t inf;
   711      ep_new(inf);
   712      // check p^order == infinity
   713      // use basic double & add as lwnaf reduces the expo modulo r
   714      ep_mul_basic(inf, p, &core_get()->ep_r);
   715      if (!ep_is_infty(inf)){
   716          ep_free(inf);
   717          return INVALID;
   718      }
   719      ep_free(inf);
   720      return VALID;
   721  }
   722  
   723  // uses a simple scalar multiplication by G1's order
   724  // to check whether a point on the curve E2 is in G2.
   725  int simple_subgroup_check_G2(const ep2_t p){
   726      ep2_t inf;
   727      ep2_new(inf);
   728      // check p^order == infinity
   729      // use basic double & add as lwnaf reduces the expo modulo r
   730      ep2_mul_basic(inf, (ep2_st*)p, &core_get()->ep_r);
   731      if (!ep2_is_infty(inf)){
   732          ep2_free(inf);
   733          return INVALID;
   734      }
   735      ep2_free(inf);
   736      return VALID;
   737  }
   738  
   739  #if (MEMBERSHIP_CHECK_G1 == BOWE)
   740  // beta such that beta^3 == 1 mod p
   741  // beta is in the Montgomery form
   742  const uint64_t beta_data[Fp_DIGITS] = { 
   743      0xcd03c9e48671f071, 0x5dab22461fcda5d2, 0x587042afd3851b95,
   744      0x8eb60ebe01bacb9e, 0x03f97d6e83d050d2, 0x18f0206554638741,
   745  };
   746  
   747  
   748  // (z^2-1)/3 with z being the parameter of bls12-381
   749  const uint64_t z2_1_by3_data[2] = { 
   750      0x0000000055555555, 0x396c8c005555e156  
   751  };
   752  
   753  // uses Bowe's check from section 3.2 from https://eprint.iacr.org/2019/814.pdf
   754  // to check whether a point on the curve E1 is in G1.
   755  int bowe_subgroup_check_G1(const ep_t p){
   756      if (ep_is_infty(p) == 1) 
   757          return VALID;
   758      fp_t b;
   759      dv_copy(b, beta_data, Fp_DIGITS); 
   760      ep_t sigma, sigma2, p_inv;
   761      ep_new(sigma);
   762      ep_new(sigma2);
   763      ep_new(p_inv);
   764  
   765      // si(p) 
   766      ep_copy(sigma, p);
   767      fp_mul(sigma[0].x, sigma[0].x, b);
   768      // -si^2(p)
   769      ep_copy(sigma2, sigma);
   770      fp_mul(sigma2[0].x, sigma2[0].x, b);
   771      fp_neg(sigma2[0].y, sigma2[0].y);
   772      ep_dbl(sigma, sigma);
   773      // -p
   774      ep_copy(p_inv, p);
   775      fp_neg(p_inv[0].y, p_inv[0].y);
   776      // (z^2-1)/3 (2*si(p) - p - si^2(p)) - si^2(p)
   777      ep_add(sigma, sigma, p_inv);
   778      ep_add(sigma, sigma, sigma2);
   779      // TODO: multiplication using a chain?
   780      ep_mul_lwnaf(sigma, sigma, &bls_prec->z2_1_by3);
   781      ep_add(sigma, sigma, sigma2);
   782      
   783      ep_free(sigma2);
   784      ep_free(p_inv);
   785      // check result against infinity
   786      if (!ep_is_infty(sigma)){
   787          ep_free(sigma);
   788          return INVALID;
   789      }
   790      ep_free(sigma);
   791      return VALID;
   792  }
   793  #endif
   794  
   795  // generates a random point in G1 and stores it in p
   796  void ep_rand_G1(ep_t p) {
   797      // multiplies G1 generator by a random scalar
   798      ep_rand(p);
   799  }
   800  
   801  // generates a random point in E1\G1 and stores it in p
   802  void ep_rand_G1complement(ep_t p) {
   803      // generate a random point in E1
   804      p->coord = BASIC;
   805      fp_set_dig(p->z, 1);
   806      do {
   807          fp_rand(p->x); // set x to a random field element
   808          byte r;
   809          rand_bytes(&r, 1);
   810          fp_zero(p->y);
   811          fp_set_bit(p->y, 0, r&1); // set y randomly to 0 or 1
   812      }
   813      while (ep_upk(p, p) == 0); // make sure p is in E1
   814  
   815      // map the point to E1\G1 by clearing G1 order
   816      ep_mul_basic(p, p, &core_get()->ep_r);
   817  
   818      assert(ep_on_curve(p));  // sanity check to make sure p is in E1
   819  }
   820  
   821  // generates a random point in G2 and stores it in p
   822  void ep2_rand_G2(ep2_t p) {
   823      // multiplies G2 generator by a random scalar
   824      ep2_rand(p);
   825  }
   826  
   827  // generates a random point in E2\G2 and stores it in p
   828  void ep2_rand_G2complement(ep2_t p) {
   829      // generate a random point in E2
   830      p->coord = BASIC;
   831      fp_set_dig(p->z[0], 1);
   832  	fp_zero(p->z[1]);
   833      do {
   834          fp2_rand(p->x); // set x to a random field element
   835          byte r;
   836          rand_bytes(&r, 1);
   837          fp2_zero(p->y);
   838          fp_set_bit(p->y[0], 0, r&1); // set y randomly to 0 or 1
   839      }
   840      while (ep2_upk(p, p) == 0); // make sure p is in E1
   841  
   842      // map the point to E1\G1 by clearing G1 order
   843      ep2_mul_basic(p, p, &core_get()->ep_r);
   844  
   845      assert(ep2_on_curve(p));  // sanity check to make sure p is in E1
   846  }
   847  
   848  // This is a testing function.
   849  // It wraps a call to a Relic macro since cgo can't call macros.
   850  void xmd_sha256(uint8_t *hash, int len_hash, uint8_t *msg, int len_msg, uint8_t *dst, int len_dst){
   851      md_xmd_sh256(hash, len_hash, msg, len_msg, dst, len_dst);
   852  }