Created
April 21, 2025 17:26
-
-
Save msinkec/f6df0729f3d34e39e64d92143a174f47 to your computer and use it in GitHub Desktop.
Cheap k*G in EVM
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX‑License‑Identifier: MIT | |
pragma solidity ^0.8.25; | |
/// Check that (Qx,Qy) = k·G on secp256k1 | |
/// | |
/// The trick is to use EVM precompile 0x01 (`ecrecover`) as a cheap | |
/// “k · G” oracle: | |
/// • Pass z = 0 (message hash) | |
/// • Pass r = Gx (x‑coordinate of the generator G) | |
/// • Pass v = 27 (because Gy is even) | |
/// • Pass s = k (the scalar we want multiplied) | |
/// | |
/// Internally ecrecover reconstructs the public key P = k·G, | |
/// then returns `keccak256(P)[12:]` as an Ethereum address. | |
/// | |
/// We recompute the same address client‑side from the caller‑supplied | |
/// point (Qx,Qy). If the two match, the point is valid. | |
library Secp256k1Verify { | |
uint256 private constant GX = | |
0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798; | |
uint8 private constant V = 27; // Gy is even | |
/// @dev returns true iff (Qx,Qy) = k·G | |
function verifyPoint( | |
uint256 k, // scalar to test | |
uint256 Qx, // x‑coordinate of claimed point | |
uint256 Qy // y‑coordinate of claimed point | |
) internal view returns (bool ok) { | |
// 1. Oracle: address derived from k·G via ecrecover | |
address oracle = ecrecover( | |
bytes32(0), // z = 0 | |
V, // parity of Gy | |
bytes32(GX), // r = Gx | |
bytes32(k) // s = k | |
); | |
// 2. Address derived from caller‑supplied (Qx,Qy) | |
address claimed = address( | |
uint160(uint256(keccak256(abi.encodePacked(Qx, Qy)))) | |
); | |
// 3. Equal ⇒ the point is correct | |
ok = (oracle == claimed); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment