Omniscia Platypus Finance Audit

Ptp Manual Review Findings

Ptp Manual Review Findings

PTP-01M: Insecure Elliptic Curve Recovery Mechanism

TypeSeverityLocation
Language SpecificMediumPtp.sol:L177

Description:

The ecrecover function is a low-level cryptographic function that should be utilized after appropriate sanitizations have been enforced on its arguments, namely on the s and v values. This is due to the inherent trait of the curve to be symmetrical on the x-axis and thus permitting signatures to be replayed with the same x value (r) but a different y value (s).

Example:

contracts/Ptp.sol
144/**
145 * @notice Triggers an approval from owner to spends
146 * @param owner The address to approve from
147 * @param spender The address to be approved
148 * @param rawAmount The number of tokens that are approved (2^256-1 means infinite)
149 * @param deadline The time at which to expire the signature
150 * @param v The recovery byte of the signature
151 * @param r Half of the ECDSA signature pair
152 * @param s Half of the ECDSA signature pair
153 */
154function permit(
155 address owner,
156 address spender,
157 uint256 rawAmount,
158 uint256 deadline,
159 uint8 v,
160 bytes32 r,
161 bytes32 s
162) external {
163 uint96 amount;
164 if (rawAmount == type(uint256).max) {
165 amount = type(uint96).max;
166 } else {
167 amount = safe96(rawAmount, 'Ptp::permit: amount exceeds 96 bits');
168 }
169
170 bytes32 domainSeparator = keccak256(
171 abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainId(), address(this))
172 );
173 bytes32 structHash = keccak256(
174 abi.encode(PERMIT_TYPEHASH, owner, spender, rawAmount, nonces[owner]++, deadline)
175 );
176 bytes32 digest = keccak256(abi.encodePacked('\x19\x01', domainSeparator, structHash));
177 address signatory = ecrecover(digest, v, r, s);
178 require(signatory != address(0), 'Ptp::permit: invalid signature');
179 require(signatory == owner, 'Ptp::permit: unauthorized');
180 require(block.timestamp <= deadline, 'Ptp::permit: signature expired');
181
182 allowances[owner][spender] = amount;
183
184 emit Approval(owner, spender, amount);
185}

Recommendation:

We advise them to be sanitized by ensuring that v is equal to either 27 or 28 (v ∈ {27, 28}) and to ensure that s is existent in the lower half order of the elliptic curve (0 < s < secp256k1n ÷ 2 + 1) by ensuring it is less than 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A1. A reference implementation of those checks can be observed in the ECDSA library of OpenZeppelin and the rationale behind those restrictions exists within Appendix F of the Yellow Paper.

Alleviation:

Proper cryptographic sanitisation was introduced for the recovery parameters.