One problem you’re may run into with pairing equalty checks onchain is the ECPAIRING
operation doesn’t allow you to directly compare arbitrary pairings without some (potentially dangerous) alterations to the verification step, also you can’t do scalar multiplication on G2 or GT elements onchain.
Recap of BLS signatures:

e(P_2,H(m)_1)_T = e(G_2, S_1)_T where _2 and _1 denote points of G1 and G2, and _T for GT.
 Offchain, you take your secret x, and do xG_2 \to P_2 (your public key).
 You then provide your public key P_2 to the onchain contract
 You then generate your signature, xH(m)_1 \to S_1
 You provide signature to onchain contract
 It verifies e(P_2,H(m)_1)_T = e(G_2, S_1)_T
The ECPAIRING
operation works as such: e(A_2, B_1) * e(C_2, D_1) = 1_T  which means you need to modify the pairing equality check in a way which doesn’t immediately seem intuitive.
from py_ecc.bn128 import *
p = curve_order
x = randint(1, p1) # out secret key
H_m = multiply(G1, randint(1, p1)) # lets pretend it's HashToPoint
P = multiply(G2, x) # our public key in G2
S = multiply(H_m, x) # our signature in G1
a = pairing(P, H_m)
b = pairing(G2, S)
assert a == b # Verify signature
To use equivalent of ECPAIRING
, you’d then do:
c = pairing(G2, neg(S))
assert a * c == FQ12.one()
To aggregate them:
y = randint(1, p1) # second secret key
Q = multiply(G2, y) # second public key
T = multiply(H_m, y) # second signature
d = pairing(add(P, Q), double(H_m))
e = pairing(double(G2, add(S,T))
assert d == e
To verify the aggregates in ECPAIRING
style:
d * pairing(double(G2) neg(add(S,T))) == FQ12.one()
I should probably add this to my solcrypto
repo lol, as it’s a useful bit of code, but anyway, in this case does using the pairing product operation introduce any vulnerabilities with the verification of aggregate BLS signatures?