LibMuon Signature hash collision
In `LibMuon` , all signatures do not distinguish between type prefixes, and `abi.encodePacked` is used when calculating the hash Cause when `abi.encodePacked`, if there is a dynamic array, different structures but the same hash value may be obtained Due to conflicting hash values, signatures can be substituted for each other, making malicious use of illegal signatures possible\\nThe following two methods are examples\\n1.verifyPrices:\\n```\\n    function verifyPrices(PriceSig memory priceSig, address partyA) internal view {\\n        MuonStorage.Layout storage muonLayout = MuonStorage.layout();\\n        require(priceSig.prices.length == priceSig.symbolIds.length, "LibMuon: Invalid length");\\n        bytes32 hash = keccak256(\\n            abi.encodePacked(\\n                muonLayout.muonAppId,\\n                priceSig.reqId,\\n                address(this),\\n              partyA,\\n              priceSig.upnl,\\n              priceSig.totalUnrealizedLoss,\\n              priceSig.symbolIds,\\n              priceSig.prices,\\n                priceSig.timestamp,\\n                getChainId()\\n            )\\n        );\\n        verifyTSSAndGateway(hash, priceSig.sigs, priceSig.gatewaySignature);\\n    }\\n```\\n\\n2.verifyPartyAUpnlAndPrice\\n```\\n    function verifyPartyAUpnlAndPrice(\\n        SingleUpnlAndPriceSig memory upnlSig,\\n        address partyA,\\n        uint256 symbolId\\n    ) internal view {\\n        MuonStorage.Layout storage muonLayout = MuonStorage.layout();\\n//        require(\\n//            block.timestamp <= upnlSig.timestamp + muonLayout.upnlValidTime,\\n//            "LibMuon: Expired signature"\\n//        );\\n        bytes32 hash = keccak256(\\n            abi.encodePacked(\\n                muonLayout.muonAppId,\\n                upnlSig.reqId,\\n                address(this),\\n              partyA,\\n              AccountStorage.layout().partyANonces[partyA],\\n              upnlSig.upnl,\\n              symbolId,\\n              upnlSig.price,\\n                upnlSig.timestamp,\\n                getChainId()\\n            )\\n        );\\n        verifyTSSAndGateway(hash, upnlSig.sigs, upnlSig.gatewaySignature);\\n    }\\n```\\n\\nWe exclude the same common part (muonAppId/reqId/address (this)/timestamp/getChainId ())\\nThrough the following simplified test code, although the structure is different, the hash value is the same at that time\\n```\\n  function test() external {\\n    address verifyPrices_partyA = address(0x1);\\n    int256 verifyPrices_upnl = 100;\\n    int256 verifyPrices_totalUnrealizedLoss = 100;\\n    uint256 [] memory verifyPrices_symbolIds = new uint256[](1);\\n    verifyPrices_symbolIds[0]=1;\\n    uint256 [] memory verifyPrices_prices = new uint256[](1);\\n    verifyPrices_prices[0]=1000;  \\n\\n    bytes32 verifyPrices  = keccak256(abi.encodePacked(\\n            verifyPrices_partyA,\\n            verifyPrices_upnl,\\n            verifyPrices_totalUnrealizedLoss,\\n            verifyPrices_symbolIds,\\n            verifyPrices_prices\\n            ));\\n\\n    address verifyPartyAUpnlAndPrice_partyA = verifyPrices_partyA;\\n    int256  verifyPartyAUpnlAndPrice_partyANonces = verifyPrices_upnl;\\n    int256  verifyPartyAUpnlAndPrice_upnl = verifyPrices_totalUnrealizedLoss;\\n    uint256 verifyPartyAUpnlAndPrice_symbolId = verifyPrices_symbolIds[0];\\n    uint256 verifyPartyAUpnlAndPrice_price = verifyPrices_prices[0];\\n\\n\\n    bytes32 verifyPartyAUpnlAndPrice  = keccak256(abi.encodePacked(\\n            verifyPartyAUpnlAndPrice_partyA,\\n            verifyPartyAUpnlAndPrice_partyANonces,\\n            verifyPartyAUpnlAndPrice_upnl,\\n            verifyPartyAUpnlAndPrice_symbolId,\\n            verifyPartyAUpnlAndPrice_price\\n            ));\\n\\n    console.log("verifyPrices == verifyPartyAUpnlAndPrice:",verifyPrices == verifyPartyAUpnlAndPrice);\\n\\n  }\\n```\\n\\n```\\n$ forge test -vvv\\n\\nRunning 1 test for test/Counter.t.sol:CounterTest\\n[PASS] test() (gas: 4991)\\nLogs:\\n  verifyPrices == verifyPartyAUpnlAndPrice: true\\n\\nTest result: ok. 1 passed; 0 failed; finished in 11.27ms\\n```\\n\\nFrom the above test example, we can see that the `verifyPrices` and `verifyPartyAUpnlAndPrice` signatures can be used interchangeably If we get a legal `verifyPartyAUpnlAndPrice` , it can be used as the signature of `verifyPrices ()` Use `partyANonces` as `upnl`, etc
It is recommended to add the prefix of the hash, or use `api.encode` Such as:\\n```\\n    function verifyPrices(PriceSig memory priceSig, address partyA) internal view {\\n        MuonStorage.Layout storage muonLayout = MuonStorage.layout();\\n        require(priceSig.prices.length == priceSig.symbolIds.length, "LibMuon: Invalid length");\\n        bytes32 hash = keccak256(\\n            abi.encodePacked(\\n+              "verifyPrices",\\n                muonLayout.muonAppId,\\n                priceSig.reqId,\\n                address(this),\\n                partyA,\\n                priceSig.upnl,\\n                priceSig.totalUnrealizedLoss,\\n                priceSig.symbolIds,\\n                priceSig.prices,\\n                priceSig.timestamp,\\n                getChainId()\\n            )\\n        );\\n        verifyTSSAndGateway(hash, priceSig.sigs, priceSig.gatewaySignature);\\n    }\\n```\\n
Signatures can be reused due to hash collisions, through illegal signatures, using illegal `unpl`, etc
```\\n    function verifyPrices(PriceSig memory priceSig, address partyA) internal view {\\n        MuonStorage.Layout storage muonLayout = MuonStorage.layout();\\n        require(priceSig.prices.length == priceSig.symbolIds.length, "LibMuon: Invalid length");\\n        bytes32 hash = keccak256(\\n            abi.encodePacked(\\n                muonLayout.muonAppId,\\n                priceSig.reqId,\\n                address(this),\\n              partyA,\\n              priceSig.upnl,\\n              priceSig.totalUnrealizedLoss,\\n              priceSig.symbolIds,\\n              priceSig.prices,\\n                priceSig.timestamp,\\n                getChainId()\\n            )\\n        );\\n        verifyTSSAndGateway(hash, priceSig.sigs, priceSig.gatewaySignature);\\n    }\\n```\\n