diff --git a/solana/programs/core-bridge/src/error.rs b/solana/programs/core-bridge/src/error.rs index 786c1d62fb..65d52cf93d 100644 --- a/solana/programs/core-bridge/src/error.rs +++ b/solana/programs/core-bridge/src/error.rs @@ -91,6 +91,9 @@ pub enum CoreBridgeError { #[msg("InstructionAtWrongIndex")] InstructionAtWrongIndex = 0x702, + #[msg("EmptySigVerifyInstruction")] + EmptySigVerifyInstruction = 0x703, + #[msg("InvalidSigVerifyInstruction")] InvalidSigVerifyInstruction = 0x704, diff --git a/solana/programs/core-bridge/src/legacy/processor/verify_signatures.rs b/solana/programs/core-bridge/src/legacy/processor/verify_signatures.rs index 4bc2b65c5f..a1806d6b69 100644 --- a/solana/programs/core-bridge/src/legacy/processor/verify_signatures.rs +++ b/solana/programs/core-bridge/src/legacy/processor/verify_signatures.rs @@ -27,7 +27,7 @@ struct SigVerifyOffsets { /// Result of parsing Sig Verify instruction data. struct SigVerifyParameters { - eth_pubkey: [u8; 20], + eth_pubkeys: Vec<[u8; 20]>, message: [u8; 32], } @@ -141,7 +141,10 @@ fn verify_signatures(ctx: Context, args: VerifySignaturesArgs) // NOTE: To avoid a redundant instructions sysvar check, we allow the deprecated method to // load the instruction data. #[allow(deprecated)] - let sig_verify_params = sysvar::instructions::load_instruction_at( + let SigVerifyParameters { + eth_pubkeys: signers, + message, + } = sysvar::instructions::load_instruction_at( usize::from(sig_verify_index), &instruction_sysvar_data, ) @@ -151,13 +154,13 @@ fn verify_signatures(ctx: Context, args: VerifySignaturesArgs) // Number of specified signers must equal the number of signatures verified in the Sig Verify // native program instruction. require_eq!( - sig_verify_params.len(), + signers.len(), guardian_indices.len(), CoreBridgeError::SignerIndicesMismatch ); // We use this message hash later on. - let message_hash = MessageHash::from(sig_verify_params[0].message); + let message_hash = MessageHash::from(message); let signature_set = &mut ctx.accounts.signature_set; // If the signature set account has not been initialized yet, establish the expected account @@ -196,7 +199,7 @@ fn verify_signatures(ctx: Context, args: VerifySignaturesArgs) // Attempt to write `true` to represent verified guardian eth pubkey. for (i, &signer_index) in guardian_indices.iter().enumerate() { require!( - sig_verify_params[i].eth_pubkey == guardians[signer_index], + signers[i] == guardians[signer_index], CoreBridgeError::InvalidGuardianKeyRecovery ); @@ -214,7 +217,7 @@ fn verify_signatures(ctx: Context, args: VerifySignaturesArgs) fn deserialize_secp256k1_ix( sig_verify_index: u16, ix: &solana_program::instruction::Instruction, -) -> Result> { +) -> Result { // Check that the program invoked is the secp256k1 program. require_keys_eq!( ix.program_id, @@ -224,48 +227,58 @@ fn deserialize_secp256k1_ix( let ix_data = &ix.data; - // First byte encodes the number of signatures. - let mut params = Vec::with_capacity(ix_data[0].into()); + // The first byte encodes the number of signatures. + let num_signatures: usize = ix_data[0].into(); + + let mut eth_pubkeys = Vec::with_capacity(num_signatures); // For each offset encoded, grab each SigVerify parameter (signature, eth pubkey, message). let mut expected_message_offset = None; - for i in 0..params.capacity() { + for i in 0..num_signatures { let offsets_idx = 1 + i * SigVerifyOffsets::INIT_SPACE; - let offsets = SigVerifyOffsets::deserialize( + let SigVerifyOffsets { + signature_offset: _, + signature_ix_index, + eth_pubkey_offset, + eth_pubkey_ix_index, + message_offset, + message_size, + message_ix_index, + } = SigVerifyOffsets::deserialize( &mut &ix_data[offsets_idx..(offsets_idx + SigVerifyOffsets::INIT_SPACE)], )?; // Because guardians sign the hash of the message body hash, this verified message must be // 32 bytes. require_eq!( - offsets.message_size, + message_size, 32, CoreBridgeError::InvalidSigVerifyInstruction ); // The instruction index must be the same for signature, eth pubkey and message. require_eq!( - u16::from(offsets.signature_ix_index), + u16::from(signature_ix_index), sig_verify_index, CoreBridgeError::InvalidSigVerifyInstruction ); require_eq!( - u16::from(offsets.eth_pubkey_ix_index), + u16::from(eth_pubkey_ix_index), sig_verify_index, CoreBridgeError::InvalidSigVerifyInstruction ); require_eq!( - u16::from(offsets.message_ix_index), + u16::from(message_ix_index), sig_verify_index, CoreBridgeError::InvalidSigVerifyInstruction ); - let eth_pubkey_offset = usize::from(offsets.eth_pubkey_offset); + let eth_pubkey_offset = usize::from(eth_pubkey_offset); let mut eth_pubkey = [0; 20]; eth_pubkey.copy_from_slice(&ix_data[eth_pubkey_offset..(eth_pubkey_offset + 20)]); // The message offset should be the same for each sig verify offsets since each signature is // for the same message. - let message_offset = usize::from(offsets.message_offset); + let message_offset = usize::from(message_offset); if let Some(expected_message_offset) = expected_message_offset { require_eq!( message_offset, @@ -274,16 +287,19 @@ fn deserialize_secp256k1_ix( ); } + eth_pubkeys.push(eth_pubkey); + expected_message_offset = Some(message_offset); + } + + if let Some(message_offset) = expected_message_offset { let mut message = [0; 32]; message.copy_from_slice(&ix_data[message_offset..(message_offset + 32)]); - params.push(SigVerifyParameters { - eth_pubkey, + Ok(SigVerifyParameters { + eth_pubkeys, message, - }); - expected_message_offset = Some(message_offset); + }) + } else { + Err(CoreBridgeError::EmptySigVerifyInstruction.into()) } - - // Done. - Ok(params) }