Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion script/SignatureChecker.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ contract SignatureCheckerScript is Script {
function run() public {
vm.startBroadcast();

signatureChecker = new SignatureChecker();
signatureChecker = new SignatureChecker(0xfdf07A5dCfa7b74f4c28DAb23eaD8B1c43Be801F);

vm.stopBroadcast();
}
Expand Down
180 changes: 0 additions & 180 deletions src/ECDSA.sol

This file was deleted.

89 changes: 76 additions & 13 deletions src/SignatureChecker.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,86 @@
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/access/Ownable.sol";
import {ECDSA} from "./ECDSA.sol";

// todo: Do we need to have some stateful capabilities?
contract SignatureChecker {
// todo Replace with our notary address
// 0xfdf07A5dCfa7b74f4c28DAb23eaD8B1c43Be801F
address public constant NOTARY_ADDRESS = address(0xfdf07A5dCfa7b74f4c28DAb23eaD8B1c43Be801F);
/// @title SignatureChecker
/// @notice A contract that verifies signatures
contract SignatureChecker is Ownable {
/// @notice Mapping of notary addresses to their validity
mapping(address => bool) public isNotary;

function isValidSignatureNow(bytes32 hash, bytes memory signature) external pure returns (bool) {
(address recovered, ECDSA.RecoverError err,) = ECDSA.tryRecover(hash, signature);
return err == ECDSA.RecoverError.NoError && recovered == NOTARY_ADDRESS;
/// valid digests for a given address
mapping(address => bytes32) public digests;

uint256 public constant BN254_MODULUS =
21888242871839275222246405745257275088548364400416034343698204186575808495617;

/// @notice Error for invalid signatures
error InvalidSignature();
/// @notice Error for invalid notary addresses
error InvalidNotary();
/// @notice Error for invalid digest
error InvalidDigest();
/// @notice Error for invalid signature length
error InvalidSignatureLength();

/// @notice Constructor configures the notary address
/// @param _notaryAddress The address of the notary to add
constructor(address _notaryAddress) Ownable(msg.sender) {
isNotary[_notaryAddress] = true;
}

/// @notice Adds a notary
/// @param _notaryAddress The address of the notary to add
function addNotary(address _notaryAddress) external onlyOwner {
isNotary[_notaryAddress] = true;
}

/// @notice Removes a notary
/// @param _notaryAddress The address of the notary to remove
function removeNotary(address _notaryAddress) external onlyOwner {
isNotary[_notaryAddress] = false;
}

// Check to see that the digest is a merkle root of a keccak256 hash of a leafs = (keccak(value), keccak(manifest))
function verify_digest(bytes32 _digest, bytes32 _manifest, bytes32 _value) internal pure returns (bool) {
bytes32 root = keccak256(abi.encodePacked(_value, _manifest));
return _digest == root;
}

/// @notice Verifies a signature
/// @param digest The hash of the data that was signed
/// @param v The recovery id
/// @param r The R value of the signature
/// @param s The S value of the signature
/// @param signer The address that signed the data
/// @param manifest The manifest of the data
/// @param value The value of the data
function verifyNotarySignature(
bytes32 digest,
uint8 v,
bytes32 r,
bytes32 s,
address signer,
bytes32 manifest,
bytes32 value
) external returns (bool) {
// check if the signer is a notary
if (!isNotary[signer]) {
revert InvalidNotary();
}
if (!verify_digest(digest, manifest, value)) {
revert InvalidDigest();
}

/// this decomposes the signature into r, s, v
// r is the x-coordinate of the curve point
// s is the y-coordinate of the curve point

// v is 0 for an even y-value
// v is 1 for an odd y-value
// v is 27 or 28 based on the y-value being even or odd
// verify the signature
address recoveredSigner = ecrecover(digest, v, r, s);
if (recoveredSigner != signer) {
revert InvalidSignature();
}
digests[msg.sender] = digest;
return true;
}
}
23 changes: 11 additions & 12 deletions test/SignatureChecker.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,20 @@ contract SignatureCheckerTest is Test {
SignatureChecker public signatureChecker;

function setUp() public {
signatureChecker = new SignatureChecker();
signatureChecker = new SignatureChecker(0xfdf07A5dCfa7b74f4c28DAb23eaD8B1c43Be801F);
}

function test_isValidSignatureNow() public view {
// Replace with our notary proof hash
bytes32 hash = keccak256("test");
function test_isValidSignatureNow() public {
// TEST vector from web-prover @ githash 2dc768e818d6f9fef575a88a2ceb80c0ed11974f
address signer = 0xfdf07A5dCfa7b74f4c28DAb23eaD8B1c43Be801F;
bytes32 digest = bytes32(0xe45537be7b5cd288c9c46b7e027b4f5a66202146012f792c1b1cabb65828994b);
bytes32 r = bytes32(0x36e820b3524e9ffffe0b4ee49e4131cc362fd161821c1dfc8757dc6186f31c96);
bytes32 s = bytes32(0x416e537065673e3028eca37cf3cbe805a3d2fafbc47235fee5e89df5f0509a9c);
uint8 v = 27;

// Replace with our notary signature
// 9039BD2DED8FD5E09B62A04A3D25D2D13F0F45F40C1B4CA6C3AECE4A71F92C1416D62561A8939ED49C97D9621C47988CF74B5B5074F89F2B2C6B9B18A6EEB1B2
// 9039BD2DED8FD5E09B62A04A3D25D2D13F0F45F40C1B4CA6C3AECE4A71F92C1416D62561A8939ED49C97D9621C47988CF74B5B5074F89F2B2C6B9B18A6EEB1B2
// There are interestingly 129 characters in this signature, the ercrecover opcode expects 65 where 32 are R, 32 are S, and 1 is V
bytes memory signature =
abi.encodePacked(bytes32(0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef));
bytes32 value = 0x8452c9b9140222b08593a26daa782707297be9f7b3e8281d7b4974769f19afd0;
bytes32 manifest = 0x7df909980a1642d0370a4a510422201ce525da6b319a7b9e9656771fa7336d5a;

// verify signature
assertEq(signatureChecker.isValidSignatureNow(hash, signature), true);
assertEq(signatureChecker.verifyNotarySignature(digest, v, r, s, signer, manifest, value), true);
}
}
9 changes: 9 additions & 0 deletions test_vectors.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"digest": "0x0ad25b24a05589ed9f2332ac85f5690c8400019f32858c2f6bf24877362d41db",
"signature": "0x304502210086c6ab86ac26bfdfd245ab65a05e90cd18afe9f810acb42532adf7570cd0ed77022017370b1c7a7d7d96155e6144a9bfc9265f81c354b1cb4af7cebe52e601dabfef",
"signature_r": "0x86c6ab86ac26bfdfd245ab65a05e90cd18afe9f810acb42532adf7570cd0ed77",
"signature_s": "0x17370b1c7a7d7d96155e6144a9bfc9265f81c354b1cb4af7cebe52e601dabfef",
"signature_v": 27,
"signer": "0xfdf07a5dcfa7b74f4c28dab23ead8b1c43be801f"
}

Loading