P256.t.sol 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. // SPDX-License-Identifier: MIT
  2. pragma solidity ^0.8.20;
  3. import {Test} from "forge-std/Test.sol";
  4. import {P256} from "@openzeppelin/contracts/utils/cryptography/P256.sol";
  5. import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
  6. import {Errors} from "@openzeppelin/contracts/utils/Errors.sol";
  7. contract P256Test is Test {
  8. /// forge-config: default.fuzz.runs = 512
  9. function testVerify(bytes32 digest, uint256 seed) public view {
  10. uint256 privateKey = _asPrivateKey(seed);
  11. (uint256 x, uint256 y) = vm.publicKeyP256(privateKey);
  12. (bytes32 r, bytes32 s) = vm.signP256(privateKey, digest);
  13. s = _ensureLowerS(s);
  14. assertTrue(P256.verify(digest, r, s, bytes32(x), bytes32(y)));
  15. assertTrue(P256.verifySolidity(digest, r, s, bytes32(x), bytes32(y)));
  16. }
  17. /// forge-config: default.fuzz.runs = 512
  18. function testRecover(bytes32 digest, uint256 seed) public view {
  19. uint256 privateKey = _asPrivateKey(seed);
  20. (uint256 x, uint256 y) = vm.publicKeyP256(privateKey);
  21. (bytes32 r, bytes32 s) = vm.signP256(privateKey, digest);
  22. s = _ensureLowerS(s);
  23. (bytes32 qx0, bytes32 qy0) = P256.recovery(digest, 0, r, s);
  24. (bytes32 qx1, bytes32 qy1) = P256.recovery(digest, 1, r, s);
  25. assertTrue((qx0 == bytes32(x) && qy0 == bytes32(y)) || (qx1 == bytes32(x) && qy1 == bytes32(y)));
  26. }
  27. function testVerifyNativeUnsupportedRIP7212(bytes32 digest, uint256 seed) public {
  28. // By default, the precompile at address 0x100 is not supported.
  29. uint256 privateKey = _asPrivateKey(seed);
  30. (uint256 x, uint256 y) = vm.publicKeyP256(privateKey);
  31. (bytes32 r, bytes32 s) = vm.signP256(privateKey, digest);
  32. s = _ensureLowerS(s);
  33. (bool success, bytes memory returndata) = address(this).call(
  34. abi.encodeCall(P256Test.verifyNative, (digest, r, s, bytes32(x), bytes32(y)))
  35. );
  36. assertFalse(success);
  37. assertEq(returndata, abi.encodeWithSelector(Errors.MissingPrecompile.selector, address(0x100)));
  38. }
  39. function _asPrivateKey(uint256 seed) private pure returns (uint256) {
  40. return bound(seed, 1, P256.N - 1);
  41. }
  42. function _ensureLowerS(bytes32 s) private pure returns (bytes32) {
  43. uint256 _s = uint256(s);
  44. unchecked {
  45. return _s > P256.N / 2 ? bytes32(P256.N - _s) : s;
  46. }
  47. }
  48. // See https://github.com/foundry-rs/foundry/issues/10237
  49. function verifyNative(bytes32 digest, bytes32 r, bytes32 s, bytes32 x, bytes32 y) external view {
  50. P256.verifyNative(digest, r, s, x, y);
  51. }
  52. }