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

     1  //go:build relic
     2  // +build relic
     3  
     4  package crypto
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  
    10  	"github.com/onflow/flow-go/crypto/hash"
    11  )
    12  
    13  // BLS multi-signature using BLS12-381 curve
    14  // ([zcash]https://github.com/zkcrypto/pairing/blob/master/src/bls12_381/README.md#bls12-381)
    15  // Pairing, ellipic curve and modular arithmetic is using Relic library.
    16  // This implementation does not include any security against side-channel attacks.
    17  
    18  // existing features:
    19  //  - the same BLS set-up in bls.go
    20  //  - Use the proof of possession scheme (PoP) to prevent against rogue public-key attack.
    21  //  - Non-interactive aggregation of private keys, public keys and signatures.
    22  //  - Non-interactive subtraction of multiple public keys from an (aggregated) public key.
    23  //  - Multi-signature verification of an aggregated signature of a single message
    24  //  under multiple public keys.
    25  //  - Multi-signature verification of an aggregated signature of multiple messages under
    26  //  multiple public keys.
    27  //  - batch verification of multiple signatures of a single message under multiple
    28  //  public keys: use a binary tree of aggregations to find the invalid signatures.
    29  
    30  // #cgo CFLAGS: -g -Wall -std=c99
    31  // #cgo LDFLAGS: -L${SRCDIR}/relic/build/lib -l relic_s
    32  // #include "bls_include.h"
    33  import "C"
    34  
    35  // the PoP hasher, used to generate and verify PoPs
    36  // The key is based on blsPOPCipherSuite which guarantees
    37  // that hash_to_field of PoP is orthogonal to all hash_to_field functions
    38  // used for signatures.
    39  var popKMAC = internalExpandMsgXOFKMAC128(blsPOPCipherSuite)
    40  
    41  // BLSGeneratePOP returns a proof of possession (PoP) for the receiver private key.
    42  //
    43  // The KMAC hasher used in the function is guaranteed to be orthogonal to all hashers used
    44  // for signatures or SPoCK proofs on this package. This means a specific domain tag is used
    45  // to generate PoP and is not used by any other application.
    46  //
    47  // The function returns:
    48  //   - (nil, notBLSKeyError) if the input key is not of type BLS BLS12-381
    49  //   - (pop, nil) otherwise
    50  func BLSGeneratePOP(sk PrivateKey) (Signature, error) {
    51  	_, ok := sk.(*prKeyBLSBLS12381)
    52  	if !ok {
    53  		return nil, notBLSKeyError
    54  	}
    55  	// sign the public key
    56  	return sk.Sign(sk.PublicKey().Encode(), popKMAC)
    57  }
    58  
    59  // BLSVerifyPOP verifies a proof of possession (PoP) for the receiver public key.
    60  //
    61  // The function internally uses the same KMAC hasher used to generate the PoP.
    62  // The hasher is guaranteed to be orthogonal to any hasher used to generate signature
    63  // or SPoCK proofs on this package.
    64  // Note that verifying a PoP against an idenity public key fails.
    65  //
    66  // The function returns:
    67  //   - (false, notBLSKeyError) if the input key is not of type BLS BLS12-381
    68  //   - (validity, nil) otherwise
    69  func BLSVerifyPOP(pk PublicKey, s Signature) (bool, error) {
    70  	_, ok := pk.(*pubKeyBLSBLS12381)
    71  	if !ok {
    72  		return false, notBLSKeyError
    73  	}
    74  	// verify the signature against the public key
    75  	return pk.Verify(s, pk.Encode(), popKMAC)
    76  }
    77  
    78  // AggregateBLSSignatures aggregates multiple BLS signatures into one.
    79  //
    80  // Signatures could be generated from the same or distinct messages, they
    81  // could also be the aggregation of other signatures.
    82  // The order of the signatures in the slice does not matter since the aggregation
    83  // is commutative. The slice should not be empty.
    84  // No G1 membership check is performed on the input signatures.
    85  //
    86  // The function returns:
    87  //   - (nil, blsAggregateEmptyListError) if no signatures are provided (input slice is empty)
    88  //   - (nil, invalidSignatureError) if a deserialization of at least one signature fails (input is an invalid serialization of a
    89  //     compressed E1 element following [zcash]
    90  //     https://www.ietf.org/archive/id/draft-irtf-cfrg-pairing-friendly-curves-08.html#name-zcash-serialization-format-).
    91  //     G1 membership is not checked.
    92  //   - (nil, error) if an unexpected error occurs
    93  //   - (aggregated_signature, nil) otherwise
    94  func AggregateBLSSignatures(sigs []Signature) (Signature, error) {
    95  	// set BLS context
    96  	blsInstance.reInit()
    97  
    98  	// check for empty list
    99  	if len(sigs) == 0 {
   100  		return nil, blsAggregateEmptyListError
   101  	}
   102  
   103  	// flatten the shares (required by the C layer)
   104  	flatSigs := make([]byte, 0, signatureLengthBLSBLS12381*len(sigs))
   105  	for i, sig := range sigs {
   106  		if len(sig) != signatureLengthBLSBLS12381 {
   107  			return nil, fmt.Errorf("signature at index %d has an invalid length: %w", i, invalidSignatureError)
   108  		}
   109  		flatSigs = append(flatSigs, sig...)
   110  	}
   111  	aggregatedSig := make([]byte, signatureLengthBLSBLS12381)
   112  
   113  	// add the points in the C layer
   114  	result := C.ep_sum_vector_byte(
   115  		(*C.uchar)(&aggregatedSig[0]),
   116  		(*C.uchar)(&flatSigs[0]),
   117  		(C.int)(len(sigs)))
   118  
   119  	switch result {
   120  	case valid:
   121  		return aggregatedSig, nil
   122  	case invalid:
   123  		return nil, invalidSignatureError
   124  	default:
   125  		return nil, fmt.Errorf("aggregating signatures failed")
   126  	}
   127  }
   128  
   129  // AggregateBLSPrivateKeys aggregates multiple BLS private keys into one.
   130  //
   131  // The order of the keys in the slice does not matter since the aggregation
   132  // is commutative. The slice should not be empty.
   133  // No check is performed on the input private keys.
   134  // Input or output private keys could be equal to the identity element (zero). Note that any
   135  // signature generated by the identity key is invalid (to avoid equivocation issues).
   136  //
   137  // The function returns:
   138  //   - (nil, notBLSKeyError) if at least one key is not of type BLS BLS12-381
   139  //   - (nil, blsAggregateEmptyListError) if no keys are provided (input slice is empty)
   140  //   - (aggregated_key, nil) otherwise
   141  func AggregateBLSPrivateKeys(keys []PrivateKey) (PrivateKey, error) {
   142  	// set BLS context
   143  	blsInstance.reInit()
   144  
   145  	// check for empty list
   146  	if len(keys) == 0 {
   147  		return nil, blsAggregateEmptyListError
   148  	}
   149  
   150  	scalars := make([]scalar, 0, len(keys))
   151  	for i, sk := range keys {
   152  		skBls, ok := sk.(*prKeyBLSBLS12381)
   153  		if !ok {
   154  			return nil, fmt.Errorf("key at index %d is invalid: %w", i, notBLSKeyError)
   155  		}
   156  		scalars = append(scalars, skBls.scalar)
   157  	}
   158  
   159  	var sum scalar
   160  	C.bn_new_wrapper((*C.bn_st)(&sum))
   161  	C.bn_sum_vector((*C.bn_st)(&sum), (*C.bn_st)(&scalars[0]),
   162  		(C.int)(len(scalars)))
   163  	return newPrKeyBLSBLS12381(&sum), nil
   164  }
   165  
   166  // AggregateBLSPublicKeys aggregate multiple BLS public keys into one.
   167  //
   168  // The order of the keys in the slice does not matter since the aggregation
   169  // is commutative. The slice should not be empty.
   170  // No check is performed on the input public keys. The input keys are guaranteed by
   171  // the package constructors to be on the G2 subgroup.
   172  // Input or output keys can be equal to the identity key. Note that any
   173  // signature verified against the identity key is invalid (to avoid equivocation issues).
   174  //
   175  // The function returns:
   176  //   - (nil, notBLSKeyError) if at least one key is not of type BLS BLS12-381
   177  //   - (nil, blsAggregateEmptyListError) no keys are provided (input slice is empty)
   178  //   - (aggregated_key, nil) otherwise
   179  func AggregateBLSPublicKeys(keys []PublicKey) (PublicKey, error) {
   180  	// set BLS context
   181  	blsInstance.reInit()
   182  
   183  	// check for empty list
   184  	if len(keys) == 0 {
   185  		return nil, blsAggregateEmptyListError
   186  	}
   187  
   188  	points := make([]pointG2, 0, len(keys))
   189  	for i, pk := range keys {
   190  		pkBLS, ok := pk.(*pubKeyBLSBLS12381)
   191  		if !ok {
   192  			return nil, fmt.Errorf("key at index %d is invalid: %w", i, notBLSKeyError)
   193  		}
   194  		points = append(points, pkBLS.point)
   195  	}
   196  
   197  	var sum pointG2
   198  	C.ep2_sum_vector((*C.ep2_st)(&sum), (*C.ep2_st)(&points[0]),
   199  		(C.int)(len(points)))
   200  
   201  	sumKey := newPubKeyBLSBLS12381(&sum)
   202  	return sumKey, nil
   203  }
   204  
   205  // IdentityBLSPublicKey returns an identity public key which corresponds to the point
   206  // at infinity in G2 (identity element of G2).
   207  func IdentityBLSPublicKey() PublicKey {
   208  	// set BLS context
   209  	blsInstance.reInit()
   210  
   211  	identity := *newPubKeyBLSBLS12381(nil)
   212  	// set the point to infinity
   213  	C.ep2_set_infty((*C.ep2_st)(&identity.point))
   214  	identity.isIdentity = true
   215  	return &identity
   216  }
   217  
   218  // RemoveBLSPublicKeys removes multiple BLS public keys from a given (aggregated) public key.
   219  //
   220  // The common use case assumes the aggregated public key was initially formed using
   221  // the keys to be removed (directly or using other aggregated forms). However the function
   222  // can still be called in different use cases.
   223  // The order of the keys to be removed in the slice does not matter since the removal
   224  // is commutative. The slice of keys to be removed can be empty.
   225  // No check is performed on the input public keys. The input keys are guaranteed by the
   226  // package constructors to be on the G2 subgroup.
   227  // Input or output keys can be equal to the identity key.
   228  //
   229  // The function returns:
   230  //   - (nil, notBLSKeyError) if at least one input key is not of type BLS BLS12-381
   231  //   - (remaining_key, nil) otherwise
   232  func RemoveBLSPublicKeys(aggKey PublicKey, keysToRemove []PublicKey) (PublicKey, error) {
   233  	// set BLS context
   234  	blsInstance.reInit()
   235  
   236  	aggPKBLS, ok := aggKey.(*pubKeyBLSBLS12381)
   237  	if !ok {
   238  		return nil, notBLSKeyError
   239  	}
   240  
   241  	pointsToSubtract := make([]pointG2, 0, len(keysToRemove))
   242  	for i, pk := range keysToRemove {
   243  		pkBLS, ok := pk.(*pubKeyBLSBLS12381)
   244  		if !ok {
   245  			return nil, fmt.Errorf("key at index %d is invalid: %w", i, notBLSKeyError)
   246  		}
   247  		pointsToSubtract = append(pointsToSubtract, pkBLS.point)
   248  	}
   249  
   250  	// check for empty list to avoid a cgo edge case
   251  	if len(keysToRemove) == 0 {
   252  		return aggKey, nil
   253  	}
   254  
   255  	var resultPoint pointG2
   256  	C.ep2_subtract_vector((*C.ep2_st)(&resultPoint), (*C.ep2_st)(&aggPKBLS.point),
   257  		(*C.ep2_st)(&pointsToSubtract[0]), (C.int)(len(pointsToSubtract)))
   258  
   259  	resultKey := newPubKeyBLSBLS12381(&resultPoint)
   260  	return resultKey, nil
   261  }
   262  
   263  // VerifyBLSSignatureOneMessage is a multi-signature verification that verifies a
   264  // BLS signature of a single message against multiple BLS public keys.
   265  //
   266  // The input signature could be generated by aggregating multiple signatures of the
   267  // message under multiple private keys. The public keys corresponding to the signing
   268  // private keys are passed as input to this function.
   269  // The caller must make sure the input public keys's proofs of possession have been
   270  // verified prior to calling this function (or each input key is sum of public keys of
   271  // which proofs of possession have been verified).
   272  //
   273  // The input hasher is the same hasher used to generate all initial signatures.
   274  // The order of the public keys in the slice does not matter.
   275  // Membership check is performed on the input signature but is not performed on the input
   276  // public keys (membership is guaranteed by using the package functions).
   277  // If the input public keys add up to the identity public key, the signature is invalid
   278  // to avoid signature equivocation issues.
   279  //
   280  // This is a special case function of VerifyBLSSignatureManyMessages, using a single
   281  // message and hasher.
   282  //
   283  // The function returns:
   284  //   - (false, nilHasherError) if hasher is nil
   285  //   - (false, invalidHasherSizeError) if hasher's output size is not 128 bytes
   286  //   - (false, notBLSKeyError) if at least one key is not of type pubKeyBLSBLS12381
   287  //   - (nil, blsAggregateEmptyListError) if input key slice is empty
   288  //   - (false, error) if an unexpected error occurs
   289  //   - (validity, nil) otherwise
   290  func VerifyBLSSignatureOneMessage(
   291  	pks []PublicKey, s Signature, message []byte, kmac hash.Hasher,
   292  ) (bool, error) {
   293  	// public key list must be non empty, this is checked internally by AggregateBLSPublicKeys
   294  	aggPk, err := AggregateBLSPublicKeys(pks)
   295  	if err != nil {
   296  		return false, fmt.Errorf("verify signature one message failed: %w", err)
   297  	}
   298  	return aggPk.Verify(s, message, kmac)
   299  }
   300  
   301  // VerifyBLSSignatureManyMessages is a multi-signature verification that verifies a
   302  // BLS signature under multiple messages and public keys.
   303  //
   304  // The input signature could be generated by aggregating multiple signatures of distinct
   305  // messages under distinct private keys. The verification is performed against the message
   306  // at index (i) and the public key at the same index (i) of the input messages and public keys.
   307  // The hasher at index (i) is used to hash the message at index (i).
   308  //
   309  // Since the package only supports the Proof of Possession scheme, the function does not enforce
   310  // input messages to be distinct. Thereore, the caller must make sure the input public keys's proofs
   311  // of possession have been verified prior to calling this function (or each input key is sum of public
   312  // keys of which proofs of possession have been verified).
   313  //
   314  // The verification is optimized to compute one pairing per distinct message, or one pairing
   315  // per distinct key, whatever way offers less pairings calls. If all messages are the same, the
   316  // function has the same behavior as VerifyBLSSignatureOneMessage. If there is one input message and
   317  // input public key, the function has the same behavior as pk.Verify.
   318  // Membership check is performed on the input signature.
   319  // In order to avoid equivocation issues, any identity public key results in the overall
   320  // signature being invalid.
   321  //
   322  // The function returns:
   323  //   - (false, nilHasherError) if a hasher is nil
   324  //   - (false, invalidHasherSizeError) if a hasher's output size is not 128 bytes
   325  //   - (false, notBLSKeyError) if at least one key is not a BLS BLS12-381 key
   326  //   - (false, invalidInputsError) if size of keys is not matching the size of messages and hashers
   327  //   - (false, blsAggregateEmptyListError) if input key slice `pks` is empty
   328  //   - (false, error) if an unexpected error occurs
   329  //   - (validity, nil) otherwise
   330  func VerifyBLSSignatureManyMessages(
   331  	pks []PublicKey, s Signature, messages [][]byte, kmac []hash.Hasher,
   332  ) (bool, error) {
   333  	// set BLS context
   334  	blsInstance.reInit()
   335  
   336  	// check signature length
   337  	if len(s) != signatureLengthBLSBLS12381 {
   338  		return false, nil
   339  	}
   340  	// check the list lengths
   341  	if len(pks) == 0 {
   342  		return false, fmt.Errorf("invalid list of public keys: %w", blsAggregateEmptyListError)
   343  	}
   344  	if len(pks) != len(messages) || len(kmac) != len(messages) {
   345  		return false, invalidInputsErrorf(
   346  			"input lists must be equal, messages are %d, keys are %d, hashers are %d",
   347  			len(messages),
   348  			len(pks),
   349  			len(kmac))
   350  	}
   351  
   352  	// compute the hashes
   353  	hashes := make([][]byte, 0, len(messages))
   354  	for i, k := range kmac {
   355  		if err := checkBLSHasher(k); err != nil {
   356  			return false, fmt.Errorf("hasher at index %d is invalid: %w ", i, err)
   357  		}
   358  		hashes = append(hashes, k.ComputeHash(messages[i]))
   359  	}
   360  
   361  	// two maps to count the type (keys or messages) with the least distinct elements.
   362  	// mapPerHash maps hashes to keys while mapPerPk maps keys to hashes.
   363  	// The comparison of the maps length minimizes the number of pairings to
   364  	// compute by aggregating either public keys or the message hashes in
   365  	// the verification equation.
   366  	mapPerHash := make(map[string][]pointG2)
   367  	mapPerPk := make(map[pointG2][][]byte)
   368  	// Note: mapPerPk is using a cgo structure as map keys which may lead to 2 equal public keys
   369  	// being considered distinct. This does not make the verification equation wrong but leads to
   370  	// computing extra pairings. This case is considered unlikely to happen since a caller is likely
   371  	// to use the same struct for a same public key.
   372  	// One way to fix this is to use the public key encoding as the map keys and store the "pointG2"
   373  	// structure with the map value, which adds more complexity and processing time.
   374  
   375  	// fill the 2 maps
   376  	for i, pk := range pks {
   377  		pkBLS, ok := pk.(*pubKeyBLSBLS12381)
   378  		if !ok {
   379  			return false, fmt.Errorf(
   380  				"public key at index %d is invalid: %w",
   381  				i, notBLSKeyError)
   382  		}
   383  		// check identity check
   384  		if pkBLS.isIdentity {
   385  			return false, nil
   386  		}
   387  
   388  		mapPerHash[string(hashes[i])] = append(mapPerHash[string(hashes[i])], pkBLS.point)
   389  		mapPerPk[pkBLS.point] = append(mapPerPk[pkBLS.point], hashes[i])
   390  	}
   391  
   392  	var verif (C.int)
   393  	//compare the 2 maps for the shortest length
   394  	if len(mapPerHash) < len(mapPerPk) {
   395  		// aggregate keys per distinct hashes
   396  		// using the linearity of the pairing on the G2 variables.
   397  		flatDistinctHashes := make([]byte, 0)
   398  		lenHashes := make([]uint32, 0)
   399  		pkPerHash := make([]uint32, 0, len(mapPerHash))
   400  		allPks := make([]pointG2, 0)
   401  		for hash, pksVal := range mapPerHash {
   402  			flatDistinctHashes = append(flatDistinctHashes, []byte(hash)...)
   403  			lenHashes = append(lenHashes, uint32(len([]byte(hash))))
   404  			pkPerHash = append(pkPerHash, uint32(len(pksVal)))
   405  			allPks = append(allPks, pksVal...)
   406  		}
   407  		verif = C.bls_verifyPerDistinctMessage(
   408  			(*C.uchar)(&s[0]),
   409  			(C.int)(len(mapPerHash)),
   410  			(*C.uchar)(&flatDistinctHashes[0]),
   411  			(*C.uint32_t)(&lenHashes[0]),
   412  			(*C.uint32_t)(&pkPerHash[0]),
   413  			(*C.ep2_st)(&allPks[0]),
   414  		)
   415  
   416  	} else {
   417  		// aggregate hashes per distinct key
   418  		// using the linearity of the pairing on the G1 variables.
   419  		distinctPks := make([]pointG2, 0, len(mapPerPk))
   420  		hashPerPk := make([]uint32, 0, len(mapPerPk))
   421  		flatHashes := make([]byte, 0)
   422  		lenHashes := make([]uint32, 0)
   423  		for pk, hashesVal := range mapPerPk {
   424  			distinctPks = append(distinctPks, pk)
   425  			hashPerPk = append(hashPerPk, uint32(len(hashesVal)))
   426  			for _, h := range hashesVal {
   427  				flatHashes = append(flatHashes, h...)
   428  				lenHashes = append(lenHashes, uint32(len(h)))
   429  			}
   430  		}
   431  
   432  		verif = C.bls_verifyPerDistinctKey(
   433  			(*C.uchar)(&s[0]),
   434  			(C.int)(len(mapPerPk)),
   435  			(*C.ep2_st)(&distinctPks[0]),
   436  			(*C.uint32_t)(&hashPerPk[0]),
   437  			(*C.uchar)(&flatHashes[0]),
   438  			(*C.uint32_t)(&lenHashes[0]))
   439  	}
   440  
   441  	switch verif {
   442  	case invalid:
   443  		return false, nil
   444  	case valid:
   445  		return true, nil
   446  	default:
   447  		return false, fmt.Errorf("signature verification failed")
   448  	}
   449  }
   450  
   451  // BatchVerifyBLSSignaturesOneMessage is a batch verification of multiple
   452  // BLS signatures of a single message against multiple BLS public keys that
   453  // is faster than verifying the signatures one by one.
   454  //
   455  // Each signature at index (i) of the input signature slice is verified against
   456  // the public key of the same index (i) in the input key slice.
   457  // The input hasher is the same used to generate all signatures.
   458  // The returned boolean slice is a slice so that the value at index (i) is true
   459  // if signature (i) verifies against public key (i), and false otherwise.
   460  //
   461  // The caller must make sure the input public keys's proofs of possession have been
   462  // verified prior to calling this function (or each input key is sum of public
   463  // keys of which proofs of possession have been verified).
   464  //
   465  // Membership checks are performed on the input signatures but are not performed
   466  // on the input public keys (which are guaranteed by the package to be on the correct
   467  // G2 subgroup).
   468  // In order to avoid equivocation issues, any identity public key results in the corresponding
   469  // signature being invalid.
   470  //
   471  // The function returns:
   472  //   - ([]false, nilHasherError) if a hasher is nil
   473  //   - ([]false, invalidHasherSizeError) if a hasher's output size is not 128 bytes
   474  //   - ([]false, notBLSKeyError) if at least one key is not of type BLS BLS12-381
   475  //   - ([]false, invalidInputsError) if size of keys is not matching the size of signatures
   476  //   - ([]false, blsAggregateEmptyListError) if input key slice is empty
   477  //   - ([]false, error) if an unexpected error occurs
   478  //   - ([]validity, nil) otherwise
   479  func BatchVerifyBLSSignaturesOneMessage(
   480  	pks []PublicKey, sigs []Signature, message []byte, kmac hash.Hasher,
   481  ) ([]bool, error) {
   482  	// set BLS context
   483  	blsInstance.reInit()
   484  
   485  	// empty list check
   486  	if len(pks) == 0 {
   487  		return []bool{}, fmt.Errorf("invalid list of public keys: %w", blsAggregateEmptyListError)
   488  	}
   489  
   490  	if len(pks) != len(sigs) {
   491  		return []bool{}, invalidInputsErrorf(
   492  			"keys length %d and signatures length %d are mismatching",
   493  			len(pks),
   494  			len(sigs))
   495  	}
   496  
   497  	verifBool := make([]bool, len(sigs))
   498  	if err := checkBLSHasher(kmac); err != nil {
   499  		return verifBool, err
   500  	}
   501  
   502  	// an invalid signature with an incorrect header but correct length
   503  	invalidSig := make([]byte, signatureLengthBLSBLS12381)
   504  	invalidSig[0] = invalidBLSSignatureHeader // incorrect header
   505  
   506  	// flatten the shares (required by the C layer)
   507  	flatSigs := make([]byte, 0, signatureLengthBLSBLS12381*len(sigs))
   508  	pkPoints := make([]pointG2, 0, len(pks))
   509  
   510  	for i, pk := range pks {
   511  		pkBLS, ok := pk.(*pubKeyBLSBLS12381)
   512  		if !ok {
   513  			return verifBool, fmt.Errorf("key at index %d is invalid: %w", i, notBLSKeyError)
   514  		}
   515  		pkPoints = append(pkPoints, pkBLS.point)
   516  
   517  		if len(sigs[i]) != signatureLengthBLSBLS12381 || pkBLS.isIdentity {
   518  			// force the signature to be invalid by replacing it with an invalid array
   519  			// that fails the deserialization in C.ep_read_bin_compact
   520  			flatSigs = append(flatSigs, invalidSig...)
   521  		} else {
   522  			flatSigs = append(flatSigs, sigs[i]...)
   523  		}
   524  	}
   525  
   526  	// hash the input to 128 bytes
   527  	h := kmac.ComputeHash(message)
   528  	verifInt := make([]byte, len(verifBool))
   529  
   530  	C.bls_batchVerify(
   531  		(C.int)(len(verifInt)),
   532  		(*C.uchar)(&verifInt[0]),
   533  		(*C.ep2_st)(&pkPoints[0]),
   534  		(*C.uchar)(&flatSigs[0]),
   535  		(*C.uchar)(&h[0]),
   536  		(C.int)(len(h)),
   537  	)
   538  
   539  	for i, v := range verifInt {
   540  		if (C.int)(v) != valid && (C.int)(v) != invalid {
   541  			return verifBool, fmt.Errorf("batch verification failed")
   542  		}
   543  		verifBool[i] = ((C.int)(v) == valid)
   544  	}
   545  
   546  	return verifBool, nil
   547  }
   548  
   549  // blsAggregateEmptyListError is returned when a list of BLS objects (e.g. signatures or keys)
   550  // is empty or nil and thereby represents an invalid input.
   551  var blsAggregateEmptyListError = errors.New("list cannot be empty")
   552  
   553  // IsBLSAggregateEmptyListError checks if err is an `blsAggregateEmptyListError`.
   554  // blsAggregateEmptyListError is returned when a BLS aggregation function is called with
   555  // an empty list which is not allowed in some aggregation cases to avoid signature equivocation
   556  // issues.
   557  func IsBLSAggregateEmptyListError(err error) bool {
   558  	return errors.Is(err, blsAggregateEmptyListError)
   559  }
   560  
   561  // notBLSKeyError is returned when a private or public key
   562  // used is not a BLS on BLS12 381 key.
   563  var notBLSKeyError = errors.New("input key has to be a BLS on BLS12-381 key")
   564  
   565  // IsNotBLSKeyError checks if err is an `notBLSKeyError`.
   566  // notBLSKeyError is returned when a private or public key
   567  // used is not a BLS on BLS12 381 key.
   568  func IsNotBLSKeyError(err error) bool {
   569  	return errors.Is(err, notBLSKeyError)
   570  }
   571  
   572  // invalidSignatureError is returned when a signature input does not serialize to a
   573  // valid element on E1 of the BLS12-381 curve (but without checking the element is on subgroup G1).
   574  var invalidSignatureError = errors.New("input signature does not deserialize to an E1 element")
   575  
   576  // IsInvalidSignatureError checks if err is an `invalidSignatureError`
   577  // invalidSignatureError is returned when a signature input does not serialize to a
   578  // valid element on E1 of the BLS12-381 curve (but without checking the element is on subgroup G1).
   579  func IsInvalidSignatureError(err error) bool {
   580  	return errors.Is(err, invalidSignatureError)
   581  }