Incorrect message digest generated in verify
function
Description
The verify
function of the merkle_root_multisig_ism
module computes a digest with the passed metadata and the user's message, and calls the verify_multisig
function with it as an argument for signature verification.
pub fn verify(&mut self, metadata: Vec<u8>, message: Vec<u8>) -> bool {
let metadata: MultisigIsmMerkleRootMetadata = metadata.into();
let message: HyperlaneMessage = message.into();
let signed_root = merkle_root_from_branch(
message.id(),
&metadata.merkle_proof,
metadata.message_index,
);
let digest = message.digest(
metadata.origin_merkle_tree_hook,
signed_root.into(),
metadata.message_index,
);
verify_multisig(
digest,
&metadata.validator_signatures,
&self.validators,
self.threshold,
)
}
At this point, the last argument of digest
should be the checkpoint index signed by the validator, metadata.signed_checkpoint_index
. However, in the current implementation, the leaf index of the message in the Merkle tree, metadata.message_index
, is being passed instead.
Impact
If the leaf index of the message in the Merkle tree on the source chain is not synchronized with the checkpoint index at the time the validator signs, a valid message may fail to be verified.
Recommendations
Modify the verify
function as below:
let digest = message.digest(
metadata.origin_merkle_tree_hook,
signed_root.into(),
- metadata.message_index,
+ metadata.signed_checkpoint_index,
);
Remediation
This issue has been acknowledged by Hyperlane, and a fix was implemented in commit 30af26bf↗.