mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-09 04:39:24 +00:00
Expand tests for ethereum-schnorr-contract
This commit is contained in:
@@ -1,7 +1,13 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
// See https://github.com/noot/schnorr-verify for implementation details
|
||||
/// @title A library for verifying Schnorr signatures
|
||||
/// @author Luke Parker <lukeparker5132@gmail.com>
|
||||
/// @author Elizabeth Binks <elizabethjbinks@gmail.com>
|
||||
/// @notice Verifies a Schnorr signature for a specified public key
|
||||
/// @dev This contract is not complete. Only certain public keys are compatible
|
||||
/// @dev See https://github.com/serai-dex/serai/blob/next/networks/ethereum/schnorr/src/tests/premise.rs for implementation details
|
||||
// TODO: Pin to a specific branch/commit once `next` is merged into `develop`
|
||||
library Schnorr {
|
||||
// secp256k1 group order
|
||||
uint256 private constant Q = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;
|
||||
@@ -11,31 +17,39 @@ library Schnorr {
|
||||
// 2) An x-coordinate < Q
|
||||
uint8 private constant KEY_PARITY = 27;
|
||||
|
||||
// px := public key x-coordinate, where the public key has an even y-coordinate
|
||||
// message := the message signed
|
||||
// c := Schnorr signature challenge
|
||||
// s := Schnorr signature solution
|
||||
function verify(bytes32 px, bytes32 message, bytes32 c, bytes32 s) internal pure returns (bool) {
|
||||
/// @notice Verifies a Schnorr signature for the specified public key
|
||||
/// @dev The y-coordinate of the public key is assumed to be even
|
||||
/// @dev The x-coordinate of the public key is assumed to be less than the order of secp256k1
|
||||
/// @dev The challenge is calculated as `keccak256(abi.encodePacked(address(R), public_key, message))` where `R` is the commitment to the Schnorr signature's nonce
|
||||
/// @param public_key The x-coordinate of the public key
|
||||
/// @param message The (hash of the) message signed
|
||||
/// @param c The challenge for the Schnorr signature
|
||||
/// @param s The response to the challenge for the Schnorr signature
|
||||
/// @return If the signature is valid
|
||||
function verify(bytes32 public_key, bytes32 message, bytes32 c, bytes32 s)
|
||||
internal
|
||||
pure
|
||||
returns (bool)
|
||||
{
|
||||
// ecrecover = (m, v, r, s) -> key
|
||||
// We instead pass the following to obtain the nonce (not the key)
|
||||
// Then we hash it and verify it matches the challenge
|
||||
bytes32 sa = bytes32(Q - mulmod(uint256(s), uint256(px), Q));
|
||||
bytes32 ca = bytes32(Q - mulmod(uint256(c), uint256(px), Q));
|
||||
// We instead pass the following to recover the Schnorr signature's nonce (not a public key)
|
||||
bytes32 sa = bytes32(Q - mulmod(uint256(s), uint256(public_key), Q));
|
||||
bytes32 ca = bytes32(Q - mulmod(uint256(c), uint256(public_key), Q));
|
||||
|
||||
/*
|
||||
The ecrecover precompile checks `r` and `s` (`px` and `ca`) are non-zero,
|
||||
banning the two keys with zero for their x-coordinate and zero challenge.
|
||||
Each has negligible probability of occuring (assuming zero x-coordinates
|
||||
are even on-curve in the first place).
|
||||
The ecrecover precompile checks `r` and `s` (`public_key` and `ca`) are non-zero, banning the
|
||||
two keys with zero for their x-coordinate and zero challenges. Each already only had a
|
||||
negligible probability of occuring (assuming zero x-coordinates are even on-curve in the first
|
||||
place).
|
||||
|
||||
`sa` is not checked to be non-zero yet it does not need to be. The inverse
|
||||
of it is never taken.
|
||||
`sa` is not checked to be non-zero yet it does not need to be. The inverse of it is never
|
||||
taken.
|
||||
*/
|
||||
address R = ecrecover(sa, KEY_PARITY, px, ca);
|
||||
address R = ecrecover(sa, KEY_PARITY, public_key, ca);
|
||||
// The ecrecover failed
|
||||
if (R == address(0)) return false;
|
||||
|
||||
// Check the signature is correct by rebuilding the challenge
|
||||
return c == keccak256(abi.encodePacked(R, px, message));
|
||||
return c == keccak256(abi.encodePacked(R, public_key, message));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,19 @@ pragma solidity ^0.8.26;
|
||||
|
||||
import "../Schnorr.sol";
|
||||
|
||||
/// @title A thin wrapper around the library for verifying Schnorr signatures to test it with
|
||||
/// @author Luke Parker <lukeparker5132@gmail.com>
|
||||
/// @author Elizabeth Binks <elizabethjbinks@gmail.com>
|
||||
contract TestSchnorr {
|
||||
/// @notice Verifies a Schnorr signature for the specified public key
|
||||
/// @dev The y-coordinate of the public key is assumed to be even
|
||||
/// @dev The x-coordinate of the public key is assumed to be less than the order of secp256k1
|
||||
/// @dev The challenge is calculated as `keccak256(abi.encodePacked(address(R), public_key, message))` where `R` is the commitment to the Schnorr signature's nonce
|
||||
/// @param public_key The x-coordinate of the public key
|
||||
/// @param message The (hash of the) message signed
|
||||
/// @param c The challenge for the Schnorr signature
|
||||
/// @param s The response to the challenge for the Schnorr signature
|
||||
/// @return If the signature is valid
|
||||
function verify(bytes32 public_key, bytes calldata message, bytes32 c, bytes32 s)
|
||||
external
|
||||
pure
|
||||
|
||||
Reference in New Issue
Block a user