From e9943ca060617d1739f3b262cf31ddd5a128a09c Mon Sep 17 00:00:00 2001 From: Asa Oines Date: Tue, 20 Dec 2022 19:06:40 -0500 Subject: [PATCH 1/7] Add MultisigIsm HIP --- HIP-2.md | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++ HIP-3.md | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 228 insertions(+) create mode 100644 HIP-2.md create mode 100644 HIP-3.md diff --git a/HIP-2.md b/HIP-2.md new file mode 100644 index 0000000..7b6e870 --- /dev/null +++ b/HIP-2.md @@ -0,0 +1,109 @@ +| hip | title | status | author | created | +| --- | -------------------- | ------ | ------ | ---------- | +| 2 | Validator signatures | Draft | asaj | 2022-12-20 | + +### **Brief Summary / Abstract** + +Defines the specification for Hyperlane validator signatures. + +### **Motivation** + +Multisigs are the simplest form of security model, one that is already supported by Hyperlane. The goal of this HIP is to standardize the `MultisigIsm` interface so that more variants may be implemented. + +### **Tech Spec** + +A `MultisigIsm` must expect the metadata passed to `accept()` to be formatted in the following way: + +``` +/** + * [ 0: 32] Merkle root + * [ 32: 36] Root index + * [ 36: 68] Origin mailbox address + * [ 68:1092] Merkle proof + * [1092:1093] Threshold + * [1093:????] Validator signatures, 65 bytes each, with length == Threshold + * [????:????] Addresses of the entire validator set, left padded to bytes32 + */ +``` + +A `MultisigIsm` should verify the the merkle proof against `root`, + +A `MultisigIsm` must implement the following interface: + +``` +interface IMultisigIsm is IInterchainSecurityModule { + /** + * @notice Returns the set of validators responsible for securing _message + * @dev Can change based on the content of _message + * @param _message Hyperlane formatted interchain message + * @return The set of validators responsible for securing _message + */ + function validators(bytes calldata _message) external view returns (address[] memory); + + /** + * @notice Returns the number of validator signatures needed to accept + * _message + * @dev Can change based on the content of _message + * @param _message Hyperlane formatted interchain message + * @return The number of signatures needed to accept _message + */ + function threshold(bytes calldata _message) external view returns (uint8); +} +``` + +When attempting to deliver a message to a recipient that uses a `MultisigIsm`, relayers should query the `validators()` and `threshold()` view functions to + +Message `recipients` should specify their `ISM` via the `interchainSecurityModule()` view function. + +``` +interface ISpecifiesInterchainSecurityModule { + /** + * @notice Returns the ISM to use for this recipient of interchain messages. + * @dev Optional, if not implemented the Mailbox's default ISM will be used. + */ + function interchainSecurityModule() external view returns (IInterchainSecurityModule); +} +``` + +The `Mailbox` contract, when delivering a message via `Mailbox.process()`, must check to see if the message recipient implements the `interchainSecurityModule()` view function. If it does, and returns a non-zero address, the `Mailbox` must call `accept()` on that address. Otherwise, it must call `accept()` on the `Mailbox's` default `ISM`. + +### **Rationale** + +Sovereign consensus allows for a modular approach to interchain security. +This allows the core protocol to be forward compatible, ensuring that Hyperlane can support new security models as they are developed. +Furthermore, it allows applications to select, configure, or invent security models that offer the most appropriate tradeoffs. + +We discuss a few of the design decisions made below. + +#### Finite ISM types + +This proposal relys on their being a finite set of ISM types that the relayer knows how to fetch and format metadata for. + +Alternatively, one could imagine a CCIP-read (or similar) based protocol for expressing arbitrary metadata, allowing for the definition of arbitrary ISMs. + +We chose this approach because we imagine a small number of ISM types being sufficiently expressive to encode most (if not all) security models. + +### **Backwards Compatibility** + +For backwards compatibility with V1, each `Mailbox` should be configured with a default `ISM`. +If `recipient.interchainSecurityModule()` reverts or returns the zero address, the default `ISM` should be used. + +### **Security Considerations** + +We believe that modularity is the best security philosophy for interchain messaging, as it has the following properties: + +- Fault isolation: The impact of `ISM` failure is limited to those applications using the `ISM`. +- Forwards compatibility: Sovereign consensus allows for security models to change as new and better solutions emerge (e.g. zkp-based light clients). +- Customizability: Applications can tailor security models to their needs, rather than relying on a one-size-fits-all solution. + +### **Future work** + +Individual `ISM` specifications should follow in future HIPs. + +Some possible ISMs to define: + +- Multisig: Given a message, specifies a set of signers and a threshold that need to have signed a merkle root, in order to accept a message proved against that root. Note that the set and threshold can vary based on message content. +- Optimistic: Given a message, specifies a set of watchers that can pause the `ISM`. Otherwise, merkle roots are accepted, and after a fraud window has expired messages can be proved against these roots. +- ZKP: Verifies a zero-knowledge-proof of the origin chain's light client protocol, with a merkle proof of the corresponding Hyperlane Outbox's merkle root. +- Routing: Routes messages to one or more other `ISMs` according to their content. +- Combo: Requires acceptance from multiple `ISMs` diff --git a/HIP-3.md b/HIP-3.md new file mode 100644 index 0000000..9687202 --- /dev/null +++ b/HIP-3.md @@ -0,0 +1,119 @@ +| hip | title | status | author | created | +| --- | ------------ | ------ | ------ | ---------- | +| 3 | Multisig ISM | Draft | asaj | 2022-12-20 | + +### **Brief Summary / Abstract** + +Defines the specification for a multisig-based interchain security module. + +### **Motivation** + +Multisigs are the simplest form of security model, one that is already supported by Hyperlane. The goal of this HIP is to standardize the `MultisigIsm` interface so that more variants may be implemented. + +### **Tech Spec** + +A `MultisigIsm` must implement the following interface. Relayers should use these view functions to understand what metadata the `ISM` needs in order to accept a message. + +``` +interface IMultisigIsm is IInterchainSecurityModule { + /** + * @notice Returns the set of validators responsible for verifying _message + * @dev Can change based on the content of _message + * @param _message Hyperlane formatted interchain message + * @return The number of signatures needed, and the array of validator + * addresses. + */ + function validatorSet( + bytes calldata _message + ) external view returns (uint8 threshold, address[] memory validators); +} +``` + +A `MultisigIsm` must expect the metadata passed to `accept()` to be formatted in the following way: + +``` +/** + * [ 0: 32] Origin mailbox merkle root + * [ 32: 36] Origin mailbox merkle root index + * [ 36: 68] Origin mailbox address + * [ 68:1092] Merkle proof of _message.id() + * [1092:1093] Threshold needed to verify _message + * [1093:????] Validator signatures, 65 bytes each, with length == Threshold. + * [????:????] Validator addresses for the entire set, left padded to bytes32 + */ +``` + +Relayers must order the validator set addresses in metadata to match the `MultisigIsm's` ordering stored on-chain. Relayers must order validator signatures in metadata similarly. + +To minimize cold SLOADs and save gas, a `MultisigIsm` should store a commitment to each validator set, and compare that commitment to the validator set provided in metadata. + +``` +/// @notice A commitment to this MultisigIsm's validator set. +/// @dev Note that more complex MultisigIsms may have validator sets and +/// thresholds that change with the message content. In those cases, the +/// corresponding commitments can be compared in verify() instead. +bytes32 public commitment; + +function verify(bytes calldata _metadata, bytes calldata _message) + external + returns (bool) +{ + uint8 _metadataThreshold = _metadata.threshold(); + address[] memory _metadataValidators = _metadata.validators(); + + bytes32 _metadataCommitment = keccak256 + bytes32 _metadataCommitment = keccak256( + abi.encodePacked(_metadataThreshold, _metadataValidators) + ); + require(_metadataCommitment == commitment); +} +``` + +A `MultisigIsm` should verify the merkle proof included in the metadata that `_message.id()` is present in the merkle tree at leaf index `_message.nonce()`, e.g.: + +``` +import {MerkleLib} from "../libs/Merkle.sol"; + +function _verifyMerkleProof( + bytes calldata _metadata, + bytes calldata _message +) internal pure returns (bool) { + // calculate the expected root based on the proof + bytes32 _calculatedRoot = MerkleLib.branchRoot( + _message.id(), + _metadata.proof(), + _message.nonce() + ); + return _calculatedRoot == _metadata.root(); +} +``` + +Finally, a `MultisigIsm` should verify that at least `metadata.threshold()` signatures were provided on `metadata.root()`, according to [HIP-TBD](https://link-to-signature-hip). + +### **Rationale** + +#### \_message as an argument to validatorSet() + +Passing `_message` as argument to `validatorSet()` allows for a broad array of customizability. + +This allows users to create `MultisigIsms` that are capable of verifying messages from many remote domains (by switching on `message.origin()`). + +It also allows users to create `MultisigIsms` that are aware of the semantic meaning of the interchain message, allowing them to e.g. increase or decrease the threshold based on message value. + +This could also be accomplished using a `RoutingIsm`, which would redirect to other ISMs based on `_message`, but that could be somewhat less efficient. For example, if you wanted to vary `threshold` based on `_message.body()` using a `RoutingIsm`, you would need to deploy and configure a `MultisigIsm` for each value of `threshold` you wanted to support. + +#### Passing the validator set as calldata + +Passing the threshold and array of validator addresses in calldata allows `MultisigIsm` implementations to be more gas efficient. Implementations can compare the set provided in calldata (4 gas / byte) against a single stored commitment (1 cold SLOAD) instead of having to look up each validator address in storage (many cold SLOADs). + +The tradeoff is that the `verify()` function becomes more complex. Implementations may choose not to use commitments, and instead read the validator set from storage, ignoring the set provided in the metadata. This is simpler but less gas efficient. + +### **Backwards Compatibility** + +This is different from the current, non-standardized implementation of `MultisigIsm`, and is not backwards compatible. Relayers should (temporarily) support both the old and new implementations. + +### **Security Considerations** + +Any `MultisigIsm` implementation that complies with this specification will be able to verify Hyperlane interchain messages. This allows for a lot of customizability, but bugs in any implementation may allow fraudulent messages to be passed to recipients that use that implementation. + +Great care should be taken when implementing an `ISM`. Hyperlane users are encouraged to use the audited implementations in hyperlane-monorepo when possible. From 965a50f19872d953c93c6d3b3cc7ec2139a94a00 Mon Sep 17 00:00:00 2001 From: Asa Oines Date: Wed, 21 Dec 2022 08:20:03 -0500 Subject: [PATCH 2/7] Add RoutingIsm --- HIP-2.md | 136 +++++++++++++++++++++++++++---------------------------- HIP-3.md | 6 ++- HIP-4.md | 54 ++++++++++++++++++++++ 3 files changed, 126 insertions(+), 70 deletions(-) create mode 100644 HIP-4.md diff --git a/HIP-2.md b/HIP-2.md index 7b6e870..066008c 100644 --- a/HIP-2.md +++ b/HIP-2.md @@ -6,104 +6,104 @@ Defines the specification for Hyperlane validator signatures. +Hyperlane validators sign messages that act as attestations of the form: + +> "On chain _d_, the mailbox contract at address _m_ had a messages tree with merkle root _r_ and message count _i_" + ### **Motivation** -Multisigs are the simplest form of security model, one that is already supported by Hyperlane. The goal of this HIP is to standardize the `MultisigIsm` interface so that more variants may be implemented. +Hyperlane validators provide the foundation for two core interchain security modules types: Multisig, and Optimistic. + +This HIP defines a standard for validator signatures so that they can be shared across different security module instances. ### **Tech Spec** -A `MultisigIsm` must expect the metadata passed to `accept()` to be formatted in the following way: +A Hyperlane validator should sign the following, in compliance with [EIP-191](https://eips.ethereum.org/EIPS/eip-191). ``` /** - * [ 0: 32] Merkle root - * [ 32: 36] Root index - * [ 36: 68] Origin mailbox address - * [ 68:1092] Merkle proof - * [1092:1093] Threshold - * [1093:????] Validator signatures, 65 bytes each, with length == Threshold - * [????:????] Addresses of the entire validator set, left padded to bytes32 + * @notice Returns the digest that Hyperlane validators should sign + * @param _domain The origin domain of the Mailbox being validated + * @param _mailbox The address of the Mailbox being validated, as bytes32 + * @param _root The merkle root that the validator is attesting to + * @param _index The message count that the validator is attesting to + * @return The digest to EIP-191 sign */ +function getDigestToSign( + uint32 _domain, + bytes32 _mailbox, + bytes32 _root, + uint32 _index +) + external + pure + returns (bytes32) +{ + + bytes32 _domainHash = keccak256( + abi.encodePacked(_domain, _mailbox, "HYPERLANE") + ); + return keccak256(abi.encodePacked(_domainHash, _root, _index)); +} ``` -A `MultisigIsm` should verify the the merkle proof against `root`, +A `ValidatorSignatureVerifier` contract implementing the following interface should be deployed to each chain supporting Hyperlane. This contract must implement the following interface and emit the `ValidatorSignature` event when verifying a signature. -A `MultisigIsm` must implement the following interface: +Verifying signatures via `ValidatorSignatureVerifier` allows watchers to more easily monitor for fraudulent validator signatures. ``` -interface IMultisigIsm is IInterchainSecurityModule { +interface IValidatorSignatureVerifier { /** - * @notice Returns the set of validators responsible for securing _message - * @dev Can change based on the content of _message - * @param _message Hyperlane formatted interchain message - * @return The set of validators responsible for securing _message + * @notice Emitted when a validator signature is verified + * @dev Used by watchtowers to detect fraudulent validators + * @param domain The origin domain of the Mailbox being validated + * @param mailbox The address of the Mailbox being validated, as bytes32 + * @param root The merkle root that the validator is attesting to + * @param index The message count that the validator is attesting to + * @param signature The 65-byte ECDSA validator signature */ - function validators(bytes calldata _message) external view returns (address[] memory); + event ValidatorSignature( + uint32 domain, + bytes32 mailbox, + bytes32 root, + uint32 index + bytes signature + ); /** - * @notice Returns the number of validator signatures needed to accept - * _message - * @dev Can change based on the content of _message - * @param _message Hyperlane formatted interchain message - * @return The number of signatures needed to accept _message + * @param _domain The origin domain of the Mailbox being validated + * @param _mailbox The address of the Mailbox being validated, as bytes32 + * @param _root The merkle root that the validator is attesting to + * @param _index The message count that the validator is attesting to + * @param _signature The 65-byte ECDSA validator signature + * @return The address of the validator that signed */ - function threshold(bytes calldata _message) external view returns (uint8); + function recoverValidatorFromSignature( + uint32 _domain, + bytes32 _mailbox, + bytes32 _root, + uint32 _index, + bytes calldata _signature + ) external returns (address); } ``` -When attempting to deliver a message to a recipient that uses a `MultisigIsm`, relayers should query the `validators()` and `threshold()` view functions to - -Message `recipients` should specify their `ISM` via the `interchainSecurityModule()` view function. - -``` -interface ISpecifiesInterchainSecurityModule { - /** - * @notice Returns the ISM to use for this recipient of interchain messages. - * @dev Optional, if not implemented the Mailbox's default ISM will be used. - */ - function interchainSecurityModule() external view returns (IInterchainSecurityModule); -} -``` - -The `Mailbox` contract, when delivering a message via `Mailbox.process()`, must check to see if the message recipient implements the `interchainSecurityModule()` view function. If it does, and returns a non-zero address, the `Mailbox` must call `accept()` on that address. Otherwise, it must call `accept()` on the `Mailbox's` default `ISM`. - ### **Rationale** -Sovereign consensus allows for a modular approach to interchain security. -This allows the core protocol to be forward compatible, ensuring that Hyperlane can support new security models as they are developed. -Furthermore, it allows applications to select, configure, or invent security models that offer the most appropriate tradeoffs. - -We discuss a few of the design decisions made below. +#### Encouraging verification through ValidatorSignatureVerifier -#### Finite ISM types +While less gas efficient, this ensures that there is a single contract that watchers can monitor for fraudulent validator signatures. -This proposal relys on their being a finite set of ISM types that the relayer knows how to fetch and format metadata for. +Fraudulent validator signatures may be used to slash the fraudulent validator, or as a trigger to disconnect an optimistic ISM. -Alternatively, one could imagine a CCIP-read (or similar) based protocol for expressing arbitrary metadata, allowing for the definition of arbitrary ISMs. - -We chose this approach because we imagine a small number of ISM types being sufficiently expressive to encode most (if not all) security models. +Encouraging a single implementation also reduces the risk that validator-signature-based ISM implementers introduce bugs in signature verification. ### **Backwards Compatibility** -For backwards compatibility with V1, each `Mailbox` should be configured with a default `ISM`. -If `recipient.interchainSecurityModule()` reverts or returns the zero address, the default `ISM` should be used. - -### **Security Considerations** - -We believe that modularity is the best security philosophy for interchain messaging, as it has the following properties: - -- Fault isolation: The impact of `ISM` failure is limited to those applications using the `ISM`. -- Forwards compatibility: Sovereign consensus allows for security models to change as new and better solutions emerge (e.g. zkp-based light clients). -- Customizability: Applications can tailor security models to their needs, rather than relying on a one-size-fits-all solution. +This format is not backwards compatible with V1, which is actually a good thing as it means validator signatures cannot be re-used. -### **Future work** +The default MultisigIsm in the V2 pre-release does not use a `ValidatorSignatureVerifier`. This can be corrected in future ISM deployements. -Individual `ISM` specifications should follow in future HIPs. - -Some possible ISMs to define: +### **Security Considerations** -- Multisig: Given a message, specifies a set of signers and a threshold that need to have signed a merkle root, in order to accept a message proved against that root. Note that the set and threshold can vary based on message content. -- Optimistic: Given a message, specifies a set of watchers that can pause the `ISM`. Otherwise, merkle roots are accepted, and after a fraud window has expired messages can be proved against these roots. -- ZKP: Verifies a zero-knowledge-proof of the origin chain's light client protocol, with a merkle proof of the corresponding Hyperlane Outbox's merkle root. -- Routing: Routes messages to one or more other `ISMs` according to their content. -- Combo: Requires acceptance from multiple `ISMs` +A bug in `ValidatorSignatureVerifier` would risk compromising all validator-signature-based ISMs. diff --git a/HIP-3.md b/HIP-3.md index 9687202..e53d4df 100644 --- a/HIP-3.md +++ b/HIP-3.md @@ -12,7 +12,9 @@ Multisigs are the simplest form of security model, one that is already supported ### **Tech Spec** -A `MultisigIsm` must implement the following interface. Relayers should use these view functions to understand what metadata the `ISM` needs in order to accept a message. +A `MultisigIsm` must return `3` in `type()`. + +A `MultisigIsm` must implement the following interface. Relayers should use these view functions to understand what metadata the `ISM` needs in order to verify a message. ``` interface IMultisigIsm is IInterchainSecurityModule { @@ -29,7 +31,7 @@ interface IMultisigIsm is IInterchainSecurityModule { } ``` -A `MultisigIsm` must expect the metadata passed to `accept()` to be formatted in the following way: +A `MultisigIsm` must expect the metadata passed to `verify()` to be formatted in the following way: ``` /** diff --git a/HIP-4.md b/HIP-4.md new file mode 100644 index 0000000..7b04d73 --- /dev/null +++ b/HIP-4.md @@ -0,0 +1,54 @@ +| hip | title | status | author | created | +| --- | ----------- | ------ | ------ | ---------- | +| 4 | Routing ISM | Draft | asaj | 2022-12-20 | + +### **Brief Summary / Abstract** + +Defines the specification for an ISM that redirects to other ISMs based on message contents. + +### **Motivation** + +Applications may want to use different security models based on message contents or application state. + +The goal of this HIP is to standardize the `RoutingIsm` interface so that users may start creating custom implementations. + +### **Tech Spec** + +A `RoutingIsm` must return `1` in `type()`. + +A `RoutingIsm` must implement the following interface. Relayers should use this view function to understand what `ISM` will be used to verify a message. + +``` +interface IRoutingIsm is IInterchainSecurityModule { + /** + * @notice Returns the address of the ISM to route to + * @dev Can change based on the content of _message, chain state, or both + * @param _message Hyperlane formatted interchain message + * @return The address of the ISM to route to + */ + function route( + bytes calldata _message + ) external view returns (IInterchainSecurityModule); +} +``` + +A `RoutingIsm` must route messages and metadata to the `ISM` returned by `route()`. + +``` +function verify(bytes calldata _metadata, bytes calldata _message) + external + returns (bool) +{ + return route(_message).verify(_metadata, _message); +} +``` + +When relayers detect a `RoutingIsm`, metadata should be formatted in accordance with the `ISM` type being routed to. + +`RoutingIsms` should avoid conditioning on frequently-changing state, as this may result in a relayer formatting metadata for the wrong `ISM`. + +### **Rationale** + +### **Backwards Compatibility** + +### **Security Considerations** From 4743cb4fdf77563851cbf730ceb5a17597d918c2 Mon Sep 17 00:00:00 2001 From: Asa Oines Date: Wed, 21 Dec 2022 08:20:39 -0500 Subject: [PATCH 3/7] Validator signatures --- HIP-3.md | 121 ------------------------------------------------------- HIP-4.md | 54 ------------------------- 2 files changed, 175 deletions(-) delete mode 100644 HIP-3.md delete mode 100644 HIP-4.md diff --git a/HIP-3.md b/HIP-3.md deleted file mode 100644 index e53d4df..0000000 --- a/HIP-3.md +++ /dev/null @@ -1,121 +0,0 @@ -| hip | title | status | author | created | -| --- | ------------ | ------ | ------ | ---------- | -| 3 | Multisig ISM | Draft | asaj | 2022-12-20 | - -### **Brief Summary / Abstract** - -Defines the specification for a multisig-based interchain security module. - -### **Motivation** - -Multisigs are the simplest form of security model, one that is already supported by Hyperlane. The goal of this HIP is to standardize the `MultisigIsm` interface so that more variants may be implemented. - -### **Tech Spec** - -A `MultisigIsm` must return `3` in `type()`. - -A `MultisigIsm` must implement the following interface. Relayers should use these view functions to understand what metadata the `ISM` needs in order to verify a message. - -``` -interface IMultisigIsm is IInterchainSecurityModule { - /** - * @notice Returns the set of validators responsible for verifying _message - * @dev Can change based on the content of _message - * @param _message Hyperlane formatted interchain message - * @return The number of signatures needed, and the array of validator - * addresses. - */ - function validatorSet( - bytes calldata _message - ) external view returns (uint8 threshold, address[] memory validators); -} -``` - -A `MultisigIsm` must expect the metadata passed to `verify()` to be formatted in the following way: - -``` -/** - * [ 0: 32] Origin mailbox merkle root - * [ 32: 36] Origin mailbox merkle root index - * [ 36: 68] Origin mailbox address - * [ 68:1092] Merkle proof of _message.id() - * [1092:1093] Threshold needed to verify _message - * [1093:????] Validator signatures, 65 bytes each, with length == Threshold. - * [????:????] Validator addresses for the entire set, left padded to bytes32 - */ -``` - -Relayers must order the validator set addresses in metadata to match the `MultisigIsm's` ordering stored on-chain. Relayers must order validator signatures in metadata similarly. - -To minimize cold SLOADs and save gas, a `MultisigIsm` should store a commitment to each validator set, and compare that commitment to the validator set provided in metadata. - -``` -/// @notice A commitment to this MultisigIsm's validator set. -/// @dev Note that more complex MultisigIsms may have validator sets and -/// thresholds that change with the message content. In those cases, the -/// corresponding commitments can be compared in verify() instead. -bytes32 public commitment; - -function verify(bytes calldata _metadata, bytes calldata _message) - external - returns (bool) -{ - uint8 _metadataThreshold = _metadata.threshold(); - address[] memory _metadataValidators = _metadata.validators(); - - bytes32 _metadataCommitment = keccak256 - bytes32 _metadataCommitment = keccak256( - abi.encodePacked(_metadataThreshold, _metadataValidators) - ); - require(_metadataCommitment == commitment); -} -``` - -A `MultisigIsm` should verify the merkle proof included in the metadata that `_message.id()` is present in the merkle tree at leaf index `_message.nonce()`, e.g.: - -``` -import {MerkleLib} from "../libs/Merkle.sol"; - -function _verifyMerkleProof( - bytes calldata _metadata, - bytes calldata _message -) internal pure returns (bool) { - // calculate the expected root based on the proof - bytes32 _calculatedRoot = MerkleLib.branchRoot( - _message.id(), - _metadata.proof(), - _message.nonce() - ); - return _calculatedRoot == _metadata.root(); -} -``` - -Finally, a `MultisigIsm` should verify that at least `metadata.threshold()` signatures were provided on `metadata.root()`, according to [HIP-TBD](https://link-to-signature-hip). - -### **Rationale** - -#### \_message as an argument to validatorSet() - -Passing `_message` as argument to `validatorSet()` allows for a broad array of customizability. - -This allows users to create `MultisigIsms` that are capable of verifying messages from many remote domains (by switching on `message.origin()`). - -It also allows users to create `MultisigIsms` that are aware of the semantic meaning of the interchain message, allowing them to e.g. increase or decrease the threshold based on message value. - -This could also be accomplished using a `RoutingIsm`, which would redirect to other ISMs based on `_message`, but that could be somewhat less efficient. For example, if you wanted to vary `threshold` based on `_message.body()` using a `RoutingIsm`, you would need to deploy and configure a `MultisigIsm` for each value of `threshold` you wanted to support. - -#### Passing the validator set as calldata - -Passing the threshold and array of validator addresses in calldata allows `MultisigIsm` implementations to be more gas efficient. Implementations can compare the set provided in calldata (4 gas / byte) against a single stored commitment (1 cold SLOAD) instead of having to look up each validator address in storage (many cold SLOADs). - -The tradeoff is that the `verify()` function becomes more complex. Implementations may choose not to use commitments, and instead read the validator set from storage, ignoring the set provided in the metadata. This is simpler but less gas efficient. - -### **Backwards Compatibility** - -This is different from the current, non-standardized implementation of `MultisigIsm`, and is not backwards compatible. Relayers should (temporarily) support both the old and new implementations. - -### **Security Considerations** - -Any `MultisigIsm` implementation that complies with this specification will be able to verify Hyperlane interchain messages. This allows for a lot of customizability, but bugs in any implementation may allow fraudulent messages to be passed to recipients that use that implementation. - -Great care should be taken when implementing an `ISM`. Hyperlane users are encouraged to use the audited implementations in hyperlane-monorepo when possible. diff --git a/HIP-4.md b/HIP-4.md deleted file mode 100644 index 7b04d73..0000000 --- a/HIP-4.md +++ /dev/null @@ -1,54 +0,0 @@ -| hip | title | status | author | created | -| --- | ----------- | ------ | ------ | ---------- | -| 4 | Routing ISM | Draft | asaj | 2022-12-20 | - -### **Brief Summary / Abstract** - -Defines the specification for an ISM that redirects to other ISMs based on message contents. - -### **Motivation** - -Applications may want to use different security models based on message contents or application state. - -The goal of this HIP is to standardize the `RoutingIsm` interface so that users may start creating custom implementations. - -### **Tech Spec** - -A `RoutingIsm` must return `1` in `type()`. - -A `RoutingIsm` must implement the following interface. Relayers should use this view function to understand what `ISM` will be used to verify a message. - -``` -interface IRoutingIsm is IInterchainSecurityModule { - /** - * @notice Returns the address of the ISM to route to - * @dev Can change based on the content of _message, chain state, or both - * @param _message Hyperlane formatted interchain message - * @return The address of the ISM to route to - */ - function route( - bytes calldata _message - ) external view returns (IInterchainSecurityModule); -} -``` - -A `RoutingIsm` must route messages and metadata to the `ISM` returned by `route()`. - -``` -function verify(bytes calldata _metadata, bytes calldata _message) - external - returns (bool) -{ - return route(_message).verify(_metadata, _message); -} -``` - -When relayers detect a `RoutingIsm`, metadata should be formatted in accordance with the `ISM` type being routed to. - -`RoutingIsms` should avoid conditioning on frequently-changing state, as this may result in a relayer formatting metadata for the wrong `ISM`. - -### **Rationale** - -### **Backwards Compatibility** - -### **Security Considerations** From d66a9829d4bfab250a1cc1fd1ddb54cfd1b3ea03 Mon Sep 17 00:00:00 2001 From: Asa Oines Date: Wed, 21 Dec 2022 08:21:19 -0500 Subject: [PATCH 4/7] Validator signatures --- HIP-2.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/HIP-2.md b/HIP-2.md index 066008c..4617cbd 100644 --- a/HIP-2.md +++ b/HIP-2.md @@ -90,6 +90,10 @@ interface IValidatorSignatureVerifier { ### **Rationale** +#### Inclusion of origin mailbox address + +Requires ISMs to verify this! Kind of a pain! + #### Encouraging verification through ValidatorSignatureVerifier While less gas efficient, this ensures that there is a single contract that watchers can monitor for fraudulent validator signatures. From 4d8413b2023ee3165a637b08f250b91f57f73996 Mon Sep 17 00:00:00 2001 From: Asa Oines Date: Wed, 21 Dec 2022 08:46:48 -0500 Subject: [PATCH 5/7] Add section on mailbox address --- HIP-2.md | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/HIP-2.md b/HIP-2.md index 4617cbd..a31c790 100644 --- a/HIP-2.md +++ b/HIP-2.md @@ -92,7 +92,43 @@ interface IValidatorSignatureVerifier { #### Inclusion of origin mailbox address -Requires ISMs to verify this! Kind of a pain! +Including the origin mailbox address in the validator signature gives it clearer semantic meaning that can be verified: + +> > "On chain _d_, the mailbox contract at address _m_ had a messages tree with merkle root _r_ and message count _i_" + +The downside is that care will need to be taken in order to ensure that malicious validators cannot manipulate the mailbox address in their signature in order to avoid the consequences of fraud. + +Take the following psuedo-code for a slashing contract: + +``` +function slash( + uint32 _domain, + bytes32 _mailbox, + bytes32 _root, + uint32 _index, + bytes calldata _signature +) external returns (address) { + address _validator = signatureVerifier.recoverValidatorFromSignature( + _domain, + _mailbox, + _root, + _index, + _signature + ); + require(IMailbox(_mailbox).rootAt(_index) != _root); + _slash(_validator); +} +``` + +Validators could avoid the consequences of signing a fraudulent checkpoint by deploying a contract that implements the `IMailbox` interface but allows them to push arbitrary messages to it. They could then sign a checkpoint for this contract and attempt to use that to deliver fraudulent messages on some destination chain. + +There are two potential mitigations: + +1. Encode remote mailbox addresses in ISMs + This would ensure that ISMs only accept messages from mailboxes that the ISM deployer knows to be a correct implementation of `Mailbox`. This ensures that `slash()` will always succeed if the validator attempts to attest to a root containing fraudulent messages. + +2. Encode supported mailboxes in the slashing contract + This would mean that signing a checkpoint for an unsupported mailbox would be considered a slashable offense. This could be done either by hardcoding addresses in storage, or hardcoding supported mailbox implementation bytecode, presuming the contents of mailbox storage do not affect the trust assumptions of outbound messages (they do not as of 2022-12-21). #### Encouraging verification through ValidatorSignatureVerifier From 8153c6966c67e857a6365d3a93fc711dfa869ca9 Mon Sep 17 00:00:00 2001 From: Asa Oines Date: Mon, 26 Dec 2022 07:26:20 -0500 Subject: [PATCH 6/7] Batching --- HIP-2.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/HIP-2.md b/HIP-2.md index a31c790..99c1909 100644 --- a/HIP-2.md +++ b/HIP-2.md @@ -70,6 +70,23 @@ interface IValidatorSignatureVerifier { bytes signature ); + /** + * @notice Emitted when one or more validator signatures are verified + * @dev Used by watchtowers to detect fraudulent validators + * @param domain The origin domain of the Mailbox being validated + * @param mailbox The address of the Mailbox being validated, as bytes32 + * @param root The merkle root that the validator is attesting to + * @param index The message count that the validator is attesting to + * @param signature 65-byte ECDSA validator signatures + */ + event ValidatorSignatures( + uint32 domain, + bytes32 mailbox, + bytes32 root, + uint32 index + bytes[] signatures + ); + /** * @param _domain The origin domain of the Mailbox being validated * @param _mailbox The address of the Mailbox being validated, as bytes32 @@ -85,6 +102,23 @@ interface IValidatorSignatureVerifier { uint32 _index, bytes calldata _signature ) external returns (address); + + /** + * @param _domain The origin domain of the Mailbox being validated + * @param _mailbox The address of the Mailbox being validated, as bytes32 + * @param _root The merkle root that the validator is attesting to + * @param _index The message count that the validator is attesting to + * @param _signatures 65-byte ECDSA validator signatures + * @return Addresses of the validators that signed + */ + function recoverValidatorsFromSignatures( + uint32 _domain, + bytes32 _mailbox, + bytes32 _root, + uint32 _index, + bytes[] calldata _signatures + ) external returns (address[] memory); + } ``` From 6d479e557f181aaafc85473a9ad96b648740e199 Mon Sep 17 00:00:00 2001 From: Asa Oines Date: Mon, 26 Dec 2022 07:27:09 -0500 Subject: [PATCH 7/7] solidity --- HIP-2.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HIP-2.md b/HIP-2.md index 99c1909..6b2af52 100644 --- a/HIP-2.md +++ b/HIP-2.md @@ -20,7 +20,7 @@ This HIP defines a standard for validator signatures so that they can be shared A Hyperlane validator should sign the following, in compliance with [EIP-191](https://eips.ethereum.org/EIPS/eip-191). -``` +```solidity /** * @notice Returns the digest that Hyperlane validators should sign * @param _domain The origin domain of the Mailbox being validated @@ -51,7 +51,7 @@ A `ValidatorSignatureVerifier` contract implementing the following interface sho Verifying signatures via `ValidatorSignatureVerifier` allows watchers to more easily monitor for fraudulent validator signatures. -``` +```solidity interface IValidatorSignatureVerifier { /** * @notice Emitted when a validator signature is verified @@ -134,7 +134,7 @@ The downside is that care will need to be taken in order to ensure that maliciou Take the following psuedo-code for a slashing contract: -``` +```solidity function slash( uint32 _domain, bytes32 _mailbox,