diff --git a/src/abstract/bls.ts b/src/abstract/bls.ts index 282cbe7..ffc8192 100644 --- a/src/abstract/bls.ts +++ b/src/abstract/bls.ts @@ -79,6 +79,11 @@ export type CurveFn = { message: Hex | ProjPointType, publicKey: Hex | ProjPointType ) => boolean; + verifyShortSignature: ( + signature: Hex | ProjPointType, + message: Hex | ProjPointType, + publicKey: Hex | ProjPointType + ) => boolean; verifyBatch: ( signature: Hex | ProjPointType, messages: (Hex | ProjPointType)[], @@ -254,6 +259,11 @@ export function bls( function normP1(point: G1Hex): G1 { return point instanceof G1.ProjectivePoint ? (point as G1) : G1.ProjectivePoint.fromHex(point); } + function normP1Hash(point: G1Hex, htfOpts?: htf.htfBasicOpts): G1 { + return point instanceof G1.ProjectivePoint + ? point + : (G1.hashToCurve(ensureBytes('point', point), htfOpts) as G1); + } function normP2(point: G2Hex): G2 { return point instanceof G2.ProjectivePoint ? point : Signature.fromHex(point); } @@ -301,6 +311,26 @@ export function bls( return Fp12.eql(exp, Fp12.ONE); } + // Checks if pairing of public key & hash is equal to pairing of generator & signature. + // e(S, G) == e(H(m), P) + function verifyShortSignature( + signature: G1Hex, + message: G1Hex, + publicKey: G2Hex, + htfOpts?: htf.htfBasicOpts + ): boolean { + const P = normP2(publicKey); + const Hm = normP1Hash(message, htfOpts); + const G = G2.ProjectivePoint.BASE; + const S = normP1(signature); + // Instead of doing 2 exponentiations, we use property of billinear maps + // and do one exp after multiplying 2 points. + const eHmP = pairing(Hm, P, false); + const eSG = pairing(S, G.negate(), false); + const exp = Fp12.finalExponentiate(Fp12.mul(eSG, eHmP)); + return Fp12.eql(exp, Fp12.ONE); + } + // Adds a bunch of public key points together. // pk1 + pk2 + pk3 = pkA function aggregatePublicKeys(publicKeys: Hex[]): Uint8Array; @@ -376,6 +406,7 @@ export function bls( sign, verify, verifyBatch, + verifyShortSignature, aggregatePublicKeys, aggregateSignatures, millerLoop,