57
57
error InsufficientSignatures ( ) ;
58
58
error InvalidGuardianIndex ( ) ;
59
59
error InvalidAddressLength ( ) ;
60
+ error InvalidSignatures ( ) ;
60
61
error VerifyVAAError ( ) ;
61
62
}
62
63
@@ -82,6 +83,7 @@ impl_debug_for_sol_error!(
82
83
NotInitialized ,
83
84
InvalidInput ,
84
85
InsufficientSignatures ,
86
+ InvalidSignatures ,
85
87
InvalidGuardianIndex ,
86
88
InvalidAddressLength ,
87
89
VerifyVAAError
@@ -100,6 +102,7 @@ pub enum WormholeError {
100
102
NotInitialized ( NotInitialized ) ,
101
103
InvalidInput ( InvalidInput ) ,
102
104
InsufficientSignatures ( InsufficientSignatures ) ,
105
+ InvalidSignatures ( InvalidSignatures ) ,
103
106
InvalidGuardianIndex ( InvalidGuardianIndex ) ,
104
107
InvalidAddressLength ( InvalidAddressLength ) ,
105
108
VerifyVAAError ( VerifyVAAError ) ,
@@ -130,6 +133,7 @@ pub struct WormholeContract {
130
133
guardian_keys : StorageMap < U256 , StorageAddress > ,
131
134
}
132
135
136
+ #[ public]
133
137
impl WormholeContract {
134
138
pub fn initialize (
135
139
& mut self ,
@@ -229,6 +233,8 @@ impl WormholeContract {
229
233
Self :: parse_vm_static ( encoded_vaa)
230
234
}
231
235
236
+ // Parsing a Wormhole VAA according to the structure defined
237
+ // by https://wormhole.com/docs/protocol/infrastructure/vaas/
232
238
fn parse_vm_static ( encoded_vaa : & [ u8 ] ) -> Result < VAA , WormholeError > {
233
239
if encoded_vaa. len ( ) < 6 {
234
240
return Err ( WormholeError :: InvalidVAAFormat ( InvalidVAAFormat { } ) ) ;
@@ -243,18 +249,23 @@ impl WormholeContract {
243
249
return Err ( WormholeError :: InvalidVAAFormat ( InvalidVAAFormat { } ) ) ;
244
250
}
245
251
246
- let guardian_set_index = u32 :: from_be_bytes ( [
247
- encoded_vaa [ cursor ] ,
248
- encoded_vaa [ cursor + 1 ] ,
249
- encoded_vaa [ cursor + 2 ] ,
250
- encoded_vaa [ cursor + 3 ] ,
251
- ] ) ;
252
+ let guardian_set_index_bytes : [ u8 ; 4 ] = encoded_vaa [ cursor..cursor + 4 ]
253
+ . try_into ( )
254
+ . map_err ( |_| WormholeError :: InvalidVAAFormat ( InvalidVAAFormat { } ) ) ? ;
255
+
256
+ let guardian_set_index = u32 :: from_be_bytes ( guardian_set_index_bytes ) ;
257
+
252
258
cursor += 4 ;
253
259
254
260
let len_signatures = encoded_vaa[ cursor] ;
255
261
cursor += 1 ;
256
262
257
263
let mut signatures = Vec :: new ( ) ;
264
+
265
+ if len_signatures > 19 {
266
+ return Err ( WormholeError :: InvalidVAAFormat ( InvalidVAAFormat { } ) ) ;
267
+ }
268
+
258
269
for _ in 0 ..len_signatures {
259
270
if cursor + 66 > encoded_vaa. len ( ) {
260
271
return Err ( WormholeError :: InvalidVAAFormat ( InvalidVAAFormat { } ) ) ;
@@ -277,20 +288,18 @@ impl WormholeContract {
277
288
return Err ( WormholeError :: InvalidVAAFormat ( InvalidVAAFormat { } ) ) ;
278
289
}
279
290
280
- let timestamp = u32:: from_be_bytes ( [
281
- encoded_vaa[ cursor] ,
282
- encoded_vaa[ cursor + 1 ] ,
283
- encoded_vaa[ cursor + 2 ] ,
284
- encoded_vaa[ cursor + 3 ] ,
285
- ] ) ;
291
+ let timestamp_bytes: [ u8 ; 4 ] = encoded_vaa[ cursor..cursor + 4 ]
292
+ . try_into ( )
293
+ . map_err ( |_| WormholeError :: InvalidVAAFormat ( InvalidVAAFormat { } ) ) ?;
294
+
295
+ let timestamp = u32:: from_be_bytes ( timestamp_bytes) ;
286
296
cursor += 4 ;
287
297
288
- let nonce = u32:: from_be_bytes ( [
289
- encoded_vaa[ cursor] ,
290
- encoded_vaa[ cursor + 1 ] ,
291
- encoded_vaa[ cursor + 2 ] ,
292
- encoded_vaa[ cursor + 3 ] ,
293
- ] ) ;
298
+ let nonce_bytes: [ u8 ; 4 ] = encoded_vaa[ cursor..cursor + 4 ]
299
+ . try_into ( )
300
+ . map_err ( |_| WormholeError :: InvalidVAAFormat ( InvalidVAAFormat { } ) ) ?;
301
+
302
+ let nonce = u32:: from_be_bytes ( nonce_bytes) ;
294
303
cursor += 4 ;
295
304
296
305
let emitter_chain_id = u16:: from_be_bytes ( [
@@ -303,16 +312,12 @@ impl WormholeContract {
303
312
emitter_address_bytes. copy_from_slice ( & encoded_vaa[ cursor..cursor + 32 ] ) ;
304
313
cursor += 32 ;
305
314
306
- let sequence = u64:: from_be_bytes ( [
307
- encoded_vaa[ cursor] ,
308
- encoded_vaa[ cursor + 1 ] ,
309
- encoded_vaa[ cursor + 2 ] ,
310
- encoded_vaa[ cursor + 3 ] ,
311
- encoded_vaa[ cursor + 4 ] ,
312
- encoded_vaa[ cursor + 5 ] ,
313
- encoded_vaa[ cursor + 6 ] ,
314
- encoded_vaa[ cursor + 7 ] ,
315
- ] ) ;
315
+ let sequence_bytes: [ u8 ; 8 ] = encoded_vaa[ cursor..cursor + 8 ]
316
+ . try_into ( )
317
+ . map_err ( |_| WormholeError :: InvalidVAAFormat ( InvalidVAAFormat { } ) ) ?;
318
+
319
+ let sequence = u64:: from_be_bytes ( sequence_bytes) ;
320
+
316
321
cursor += 8 ;
317
322
318
323
let consistency_level = encoded_vaa[ cursor] ;
@@ -345,10 +350,13 @@ impl WormholeContract {
345
350
&& guardian_set. expiration_time > 0 {
346
351
return Err ( WormholeError :: GuardianSetExpired ( GuardianSetExpired { } ) )
347
352
}
353
+
354
+ let num_guardians : u32 = guardian_set. keys . len ( ) . try_into ( ) . map_err ( |_| WormholeError :: InvalidInput ( InvalidInput { } ) ) ?;
348
355
349
- let required_signatures = Self :: quorum ( guardian_set. keys . len ( ) as u32 ) ;
356
+ let required_signatures = Self :: quorum ( num_guardians) ;
357
+ let num_signatures : u32 = vaa. signatures . len ( ) . try_into ( ) . map_err ( |_| WormholeError :: InvalidInput ( InvalidInput { } ) ) ?;
350
358
351
- if vaa . signatures . len ( ) < required_signatures as usize {
359
+ if num_signatures < required_signatures {
352
360
return Err ( WormholeError :: InsufficientSignatures ( InsufficientSignatures { } ) ) ;
353
361
}
354
362
@@ -362,11 +370,16 @@ impl WormholeContract {
362
370
}
363
371
last_guardian_index = Some ( signature. guardian_index ) ;
364
372
365
- if signature. guardian_index as usize >= guardian_set. keys . len ( ) {
373
+ let index: usize = signature
374
+ . guardian_index
375
+ . try_into ( )
376
+ . map_err ( |_| WormholeError :: InvalidGuardianIndex ( InvalidGuardianIndex { } ) ) ?;
377
+
378
+ if index >= guardian_set. keys . len ( ) {
366
379
return Err ( WormholeError :: InvalidGuardianIndex ( InvalidGuardianIndex { } ) ) ;
367
380
}
368
381
369
- let guardian_address = guardian_set. keys [ signature . guardian_index as usize ] ;
382
+ let guardian_address = guardian_set. keys [ index ] ;
370
383
let hashed_vaa_hash: FixedBytes < 32 > = FixedBytes :: from ( keccak256 ( vaa. hash ) ) ;
371
384
372
385
match self . verify_signature ( & hashed_vaa_hash, & signature. signature , guardian_address) {
@@ -404,7 +417,9 @@ impl WormholeContract {
404
417
self . guardian_set_expiry . setter ( U256 :: from ( set_index) ) . set ( U256 :: from ( expiration_time) ) ;
405
418
406
419
for ( i, guardian) in guardians. iter ( ) . enumerate ( ) {
407
- let key = self . compute_guardian_key ( set_index, i as u8 ) ;
420
+ let i_u8: u8 = i. try_into ( )
421
+ . map_err ( |_| WormholeError :: InvalidGuardianIndex ( InvalidGuardianIndex { } ) ) ?;
422
+ let key = self . compute_guardian_key ( set_index, i_u8) ;
408
423
self . guardian_keys . setter ( key) . set ( * guardian) ;
409
424
}
410
425
@@ -424,7 +439,10 @@ impl WormholeContract {
424
439
425
440
let secp = Secp256k1 :: new ( ) ;
426
441
427
- let recid = RecoveryId :: try_from ( signature[ 64 ] as i32 )
442
+ let recid_raw_i32: i32 = signature[ 64 ] . try_into ( )
443
+ . map_err ( |_| WormholeError :: InvalidGuardianIndex ( InvalidGuardianIndex { } ) ) ?;
444
+
445
+ let recid = RecoveryId :: try_from ( recid_raw_i32)
428
446
. map_err ( |_| WormholeError :: InvalidSignature ( InvalidSignature { } ) ) ?;
429
447
let recoverable_sig = RecoverableSignature :: from_compact ( & signature[ ..64 ] , recid)
430
448
. map_err ( |_| WormholeError :: InvalidSignature ( InvalidSignature { } ) ) ?;
@@ -453,7 +471,13 @@ impl WormholeContract {
453
471
let mut keys = Vec :: new ( ) ;
454
472
let size_u32: u32 = size. try_into ( ) . unwrap_or ( 0 ) ;
455
473
for i in 0 ..size_u32 {
456
- let key = self . compute_guardian_key ( index, i as u8 ) ;
474
+ let i_u8: u8 = match i. try_into ( ) {
475
+ Ok ( val) => val,
476
+ Err ( _) => {
477
+ return None ;
478
+ }
479
+ } ;
480
+ let key = self . compute_guardian_key ( index, i_u8) ;
457
481
let guardian_address = self . guardian_keys . getter ( key) . get ( ) ;
458
482
keys. push ( guardian_address) ;
459
483
}
@@ -705,7 +729,7 @@ mod tests {
705
729
}
706
730
}
707
731
708
- fn create_valid_guardian_signature ( guardian_index : u8 , hash : & FixedBytes < 32 > ) -> GuardianSignature {
732
+ fn create_valid_guardian_signature ( guardian_index : u8 , hash : & FixedBytes < 32 > ) -> Result < GuardianSignature , WormholeError > {
709
733
// Select a test guardian secret key
710
734
let secret: SecretKey = match guardian_index {
711
735
0 => test_guardian_secret1 ( ) ,
@@ -724,18 +748,23 @@ mod tests {
724
748
725
749
// Build Ethereum-compatible 65-byte signature (r || s || v)
726
750
let mut signature_bytes = [ 0u8 ; 65 ] ;
727
- signature_bytes[ ..64 ] . copy_from_slice ( & sig_bytes) ;
751
+ signature_bytes
752
+ . get_mut ( ..64 )
753
+ . ok_or ( WormholeError :: InvalidInput ( InvalidInput { } ) ) ?
754
+ . copy_from_slice ( & sig_bytes) ;
755
+
728
756
signature_bytes[ 64 ] = match recovery_id {
729
757
RecoveryId :: Zero => 27 ,
730
758
RecoveryId :: One => 28 ,
731
759
RecoveryId :: Two => 29 ,
732
760
RecoveryId :: Three => 30 ,
761
+ _ => return Err ( WormholeError :: InvalidInput ( InvalidInput { } ) ) ,
733
762
} ;
734
763
735
- GuardianSignature {
764
+ Ok ( GuardianSignature {
736
765
guardian_index,
737
766
signature : FixedBytes :: from ( signature_bytes) ,
738
- }
767
+ } )
739
768
}
740
769
741
770
fn create_guardian_signature ( guardian_index : u8 ) -> GuardianSignature {
@@ -932,7 +961,13 @@ mod tests {
932
961
let _contract = deploy_with_mainnet_guardians ( ) ;
933
962
934
963
for i in 0 ..10 {
935
- let corrupted_data = corrupted_vaa ( vec ! [ 1 , 0 , 0 , 1 , 0 , 0 ] , i, i as u8 , ( i * 2 ) as u8 ) ;
964
+ let i_u8: u8 = match i. try_into ( ) {
965
+ Ok ( val) => val,
966
+ Err ( _) => {
967
+ panic ! ( "Invalid index" ) ;
968
+ }
969
+ } ;
970
+ let corrupted_data = corrupted_vaa ( vec ! [ 1 , 0 , 0 , 1 , 0 , 0 ] , i, i_u8, ( i_u8 * 2 ) ) ;
936
971
let result = WormholeContract :: parse_vm_static ( & corrupted_data) ;
937
972
assert ! ( result. is_err( ) ) ;
938
973
}
@@ -943,8 +978,14 @@ mod tests {
943
978
let contract = deploy_with_mainnet_guardians ( ) ;
944
979
945
980
for i in 0 ..5 {
981
+ let i_u8: u8 = match i. try_into ( ) {
982
+ Ok ( val) => val,
983
+ Err ( _) => {
984
+ panic ! ( "Invalid index" ) ;
985
+ }
986
+ } ;
946
987
let base_vaa = vec ! [ 1 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ;
947
- let corrupted_data = corrupted_vaa ( base_vaa, i, i as u8 , ( i * 3 ) as u8 ) ;
988
+ let corrupted_data = corrupted_vaa ( base_vaa, i, i_u8 , ( i_u8 * 3 ) ) ;
948
989
let result = WormholeContract :: parse_vm_static ( & corrupted_data) ;
949
990
assert ! ( result. is_err( ) ) ;
950
991
}
@@ -1032,8 +1073,8 @@ mod tests {
1032
1073
version : 1 ,
1033
1074
guardian_set_index : 0 ,
1034
1075
signatures : vec ! [
1035
- create_valid_guardian_signature( 0 , & hash) ,
1036
- create_valid_guardian_signature( 1 , & hash) ,
1076
+ create_valid_guardian_signature( 0 , & hash) . unwrap ( ) ,
1077
+ create_valid_guardian_signature( 1 , & hash) . unwrap ( ) ,
1037
1078
] ,
1038
1079
timestamp : 0 ,
1039
1080
nonce : 0 ,
0 commit comments