mirror of
https://github.com/serai-dex/serai.git
synced 2024-12-24 20:49:27 +00:00
37 lines
1.2 KiB
Solidity
37 lines
1.2 KiB
Solidity
|
//SPDX-License-Identifier: AGPLv3
|
||
|
pragma solidity ^0.8.0;
|
||
|
|
||
|
// see https://github.com/noot/schnorr-verify for implementation details
|
||
|
contract Schnorr {
|
||
|
// secp256k1 group order
|
||
|
uint256 constant public Q =
|
||
|
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;
|
||
|
|
||
|
// parity := public key y-coord parity (27 or 28)
|
||
|
// px := public key x-coord
|
||
|
// message := 32-byte message
|
||
|
// s := schnorr signature
|
||
|
// e := schnorr signature challenge
|
||
|
function verify(
|
||
|
uint8 parity,
|
||
|
bytes32 px,
|
||
|
bytes32 message,
|
||
|
bytes32 s,
|
||
|
bytes32 e
|
||
|
) public view returns (bool) {
|
||
|
// ecrecover = (m, v, r, s);
|
||
|
bytes32 sp = bytes32(Q - mulmod(uint256(s), uint256(px), Q));
|
||
|
bytes32 ep = bytes32(Q - mulmod(uint256(e), uint256(px), Q));
|
||
|
|
||
|
require(sp != 0);
|
||
|
// the ecrecover precompile implementation checks that the `r` and `s`
|
||
|
// inputs are non-zero (in this case, `px` and `ep`), thus we don't need to
|
||
|
// check if they're zero.will make me
|
||
|
address R = ecrecover(sp, parity, px, ep);
|
||
|
require(R != address(0), "ecrecover failed");
|
||
|
return e == keccak256(
|
||
|
abi.encodePacked(R, uint8(parity), px, block.chainid, message)
|
||
|
);
|
||
|
}
|
||
|
}
|