1
1
import blst from "@chainsafe/blst" ;
2
2
import { 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" ;
4
4
import { PublicKey } from "./publicKey.js" ;
5
5
import { EmptyAggregateError , ZeroSignatureError } from "../errors.js" ;
6
6
@@ -19,54 +19,83 @@ export class Signature implements ISignature {
19
19
return this . fromBytes ( hexToBytes ( hex ) ) ;
20
20
}
21
21
22
- static aggregate ( signatures : Signature [ ] ) : Signature {
22
+ static aggregate ( signatures : SignatureArg [ ] ) : Signature {
23
23
if ( signatures . length === 0 ) {
24
24
throw new EmptyAggregateError ( ) ;
25
25
}
26
26
27
- const agg = blst . aggregateSignatures ( signatures . map ( ( { value } ) => value ) ) ;
27
+ const agg = blst . aggregateSignatures ( signatures . map ( Signature . convertToBlstSignatureArg ) ) ;
28
28
return new Signature ( agg ) ;
29
29
}
30
30
31
- static verifyMultipleSignatures ( sets : { publicKey : PublicKey ; message : Uint8Array ; signature : Signature } [ ] ) : boolean {
31
+ static verifyMultipleSignatures ( sets : SignatureSet [ ] ) : boolean {
32
32
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
+ } ) )
35
48
) ;
36
49
}
37
50
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
+
38
56
/**
39
57
* Implemented for SecretKey to be able to call .sign()
40
58
*/
41
59
private static friendBuild ( sig : blst . Signature ) : Signature {
42
60
return new Signature ( sig ) ;
43
61
}
44
62
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
+
46
67
// Individual infinity signatures are NOT okay. Aggregated signatures MAY be infinity
47
68
if ( this . value . isInfinity ( ) ) {
48
69
throw new ZeroSignatureError ( ) ;
49
70
}
71
+ return blst . verify ( message , PublicKey . convertToBlstPublicKeyArg ( publicKey ) , this . value ) ;
72
+ }
50
73
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 ) ;
53
76
}
54
77
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 ) ;
62
80
}
63
81
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 ) ;
70
99
}
71
100
72
101
toBytes ( format ?: PointFormat ) : Uint8Array {
@@ -85,14 +114,37 @@ export class Signature implements ISignature {
85
114
return new Signature ( this . value . multiplyBy ( bytes ) ) ;
86
115
}
87
116
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
+
89
131
// If this set is simply an infinity signature and infinity publicKey then skip verification.
90
132
// This has the effect of always declaring that this sig/publicKey combination is valid.
91
133
// 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
+ }
94
144
}
95
145
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 ) ;
97
149
}
98
150
}
0 commit comments