11import blst from "@chainsafe/blst" ;
22import { bytesToHex , hexToBytes } from "../helpers/index.js" ;
3- import { CoordType , PointFormat , Signature as ISignature } from "../types.js" ;
3+ import { SignatureSet , CoordType , PointFormat , Signature as ISignature , PublicKeyArg , SignatureArg } from "../types.js" ;
44import { PublicKey } from "./publicKey.js" ;
55import { EmptyAggregateError , ZeroSignatureError } from "../errors.js" ;
66
@@ -19,54 +19,83 @@ export class Signature implements ISignature {
1919 return this . fromBytes ( hexToBytes ( hex ) ) ;
2020 }
2121
22- static aggregate ( signatures : Signature [ ] ) : Signature {
22+ static aggregate ( signatures : SignatureArg [ ] ) : Signature {
2323 if ( signatures . length === 0 ) {
2424 throw new EmptyAggregateError ( ) ;
2525 }
2626
27- const agg = blst . aggregateSignatures ( signatures . map ( ( { value } ) => value ) ) ;
27+ const agg = blst . aggregateSignatures ( signatures . map ( Signature . convertToBlstSignatureArg ) ) ;
2828 return new Signature ( agg ) ;
2929 }
3030
31- static verifyMultipleSignatures ( sets : { publicKey : PublicKey ; message : Uint8Array ; signature : Signature } [ ] ) : boolean {
31+ static verifyMultipleSignatures ( sets : SignatureSet [ ] ) : boolean {
3232 return blst . verifyMultipleAggregateSignatures (
33- // @ts -expect-error Need to hack type to get access to the private `value`
34- sets . map ( ( s ) => ( { message : s . message , publicKey : s . publicKey . value , signature : s . signature . value } ) )
33+ sets . map ( ( set ) => ( {
34+ message : set . message ,
35+ publicKey : PublicKey . convertToBlstPublicKeyArg ( set . publicKey ) ,
36+ signature : Signature . convertToBlstSignatureArg ( set . signature ) ,
37+ } ) )
38+ ) ;
39+ }
40+
41+ static asyncVerifyMultipleSignatures ( sets : SignatureSet [ ] ) : Promise < boolean > {
42+ return blst . asyncVerifyMultipleAggregateSignatures (
43+ sets . map ( ( set ) => ( {
44+ message : set . message ,
45+ publicKey : PublicKey . convertToBlstPublicKeyArg ( set . publicKey ) ,
46+ signature : Signature . convertToBlstSignatureArg ( set . signature ) ,
47+ } ) )
3548 ) ;
3649 }
3750
51+ static convertToBlstSignatureArg ( signature : SignatureArg ) : blst . SignatureArg {
52+ // Need to cast to blst-native Signature instead of ISignature
53+ return signature instanceof Uint8Array ? signature : ( signature as Signature ) . value ;
54+ }
55+
3856 /**
3957 * Implemented for SecretKey to be able to call .sign()
4058 */
4159 private static friendBuild ( sig : blst . Signature ) : Signature {
4260 return new Signature ( sig ) ;
4361 }
4462
45- verify ( publicKey : PublicKey , message : Uint8Array ) : boolean {
63+ verify ( publicKey : PublicKeyArg , message : Uint8Array ) : boolean {
64+ // TODO (@matthewkeil) The note in aggregateVerify and the checks in this method
65+ // do not seem to go together. Need to check the spec further.
66+
4667 // Individual infinity signatures are NOT okay. Aggregated signatures MAY be infinity
4768 if ( this . value . isInfinity ( ) ) {
4869 throw new ZeroSignatureError ( ) ;
4970 }
71+ return blst . verify ( message , PublicKey . convertToBlstPublicKeyArg ( publicKey ) , this . value ) ;
72+ }
5073
51- // @ts -expect-error Need to hack type to get access to the private `value`
52- return blst . verify ( message , publicKey . value , this . value ) ;
74+ verifyAggregate ( publicKeys : PublicKeyArg [ ] , message : Uint8Array ) : boolean {
75+ return blst . fastAggregateVerify ( message , publicKeys . map ( PublicKey . convertToBlstPublicKeyArg ) , this . value ) ;
5376 }
5477
55- verifyAggregate ( publicKeys : PublicKey [ ] , message : Uint8Array ) : boolean {
56- return blst . fastAggregateVerify (
57- message ,
58- // @ts -expect-error Need to hack type to get access to the private `value`
59- publicKeys . map ( ( pk ) => pk . value ) ,
60- this . value
61- ) ;
78+ verifyMultiple ( publicKeys : PublicKeyArg [ ] , messages : Uint8Array [ ] ) : boolean {
79+ return this . aggregateVerify ( publicKeys , messages , false ) ;
6280 }
6381
64- verifyMultiple ( publicKeys : PublicKey [ ] , messages : Uint8Array [ ] ) : boolean {
65- return this . aggregateVerify (
66- messages ,
67- // @ts -expect-error Need to hack type to get access to the private `value`
68- publicKeys . map ( ( pk ) => pk . value )
69- ) ;
82+ async asyncVerify ( publicKey : PublicKeyArg , message : Uint8Array ) : Promise < boolean > {
83+ // TODO (@matthewkeil) The note in aggregateVerify and the checks in this method
84+ // do not seem to go together. Need to check the spec further.
85+
86+ // Individual infinity signatures are NOT okay. Aggregated signatures MAY be infinity
87+ if ( this . value . isInfinity ( ) ) {
88+ throw new ZeroSignatureError ( ) ;
89+ }
90+ return blst . asyncVerify ( message , PublicKey . convertToBlstPublicKeyArg ( publicKey ) , this . value ) ;
91+ }
92+
93+ async asyncVerifyAggregate ( publicKeys : PublicKeyArg [ ] , message : Uint8Array ) : Promise < boolean > {
94+ return blst . asyncFastAggregateVerify ( message , publicKeys . map ( PublicKey . convertToBlstPublicKeyArg ) , this . value ) ;
95+ }
96+
97+ async asyncVerifyMultiple ( publicKeys : PublicKeyArg [ ] , messages : Uint8Array [ ] ) : Promise < boolean > {
98+ return this . aggregateVerify ( publicKeys , messages , true ) ;
7099 }
71100
72101 toBytes ( format ?: PointFormat ) : Uint8Array {
@@ -85,14 +114,37 @@ export class Signature implements ISignature {
85114 return new Signature ( this . value . multiplyBy ( bytes ) ) ;
86115 }
87116
88- private aggregateVerify ( msgs : Uint8Array [ ] , pks : blst . PublicKey [ ] ) : boolean {
117+ private aggregateVerify < T extends false > ( publicKeys : PublicKeyArg [ ] , messages : Uint8Array [ ] , runAsync : T ) : boolean ;
118+ private aggregateVerify < T extends true > (
119+ publicKeys : PublicKeyArg [ ] ,
120+ messages : Uint8Array [ ] ,
121+ runAsync : T
122+ ) : Promise < boolean > ;
123+ private aggregateVerify < T extends boolean > (
124+ publicKeys : PublicKeyArg [ ] ,
125+ messages : Uint8Array [ ] ,
126+ runAsync : T
127+ ) : Promise < boolean > | boolean {
128+ // TODO (@matthewkeil) The note in verify and the checks in this method
129+ // do not seem to go together. Need to check the spec further.
130+
89131 // If this set is simply an infinity signature and infinity publicKey then skip verification.
90132 // This has the effect of always declaring that this sig/publicKey combination is valid.
91133 // for Eth2.0 specs tests
92- if ( this . value . isInfinity ( ) && pks . length === 1 && pks [ 0 ] . isInfinity ( ) ) {
93- return true ;
134+ if ( publicKeys . length === 1 ) {
135+ const publicKey = publicKeys [ 0 ] ;
136+ // eslint-disable-next-line prettier/prettier
137+ const pk : PublicKey = publicKey instanceof Uint8Array
138+ ? PublicKey . fromBytes ( publicKey )
139+ : ( publicKey as PublicKey ) ; // need to cast to blst-native key instead of IPublicKey
140+ // @ts -expect-error Need to hack type to get access to the private `value`
141+ if ( this . value . isInfinity ( ) && pk . value . isInfinity ( ) ) {
142+ return runAsync ? Promise . resolve ( true ) : true ;
143+ }
94144 }
95145
96- return blst . aggregateVerify ( msgs , pks , this . value ) ;
146+ return runAsync
147+ ? blst . asyncAggregateVerify ( messages , publicKeys . map ( PublicKey . convertToBlstPublicKeyArg ) , this . value )
148+ : blst . aggregateVerify ( messages , publicKeys . map ( PublicKey . convertToBlstPublicKeyArg ) , this . value ) ;
97149 }
98150}
0 commit comments