-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(protocol): Separate proof verification to a standalone, deployed contract #13794
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// SPDX-License-Identifier: MIT | ||
// _____ _ _ _ _ | ||
// |_ _|_ _(_) |_____ | | __ _| |__ ___ | ||
// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< | ||
// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ | ||
|
||
pragma solidity ^0.8.18; | ||
|
||
import {TaikoData} from "./TaikoData.sol"; | ||
import {AddressResolver} from "../common/AddressResolver.sol"; | ||
|
||
interface IProofVerifier { | ||
/** | ||
* Verifying proof via the ProofVerifier contract | ||
* | ||
* @param instance Hashed public input | ||
* @param blockProofs Proof array | ||
* @param resolver Current (up-to-date) address resolver | ||
*/ | ||
function verifyProofs( | ||
bytes32 instance, | ||
TaikoData.TypedProof[] calldata blockProofs, | ||
AddressResolver resolver | ||
) external; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
// SPDX-License-Identifier: MIT | ||
// _____ _ _ _ _ | ||
// |_ _|_ _(_) |_____ | | __ _| |__ ___ | ||
// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< | ||
// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ | ||
|
||
pragma solidity ^0.8.18; | ||
|
||
import {AddressResolver} from "../common/AddressResolver.sol"; | ||
import {Proxied} from "../common/Proxied.sol"; | ||
import {TaikoErrors} from "./TaikoErrors.sol"; | ||
import {TaikoData} from "./TaikoData.sol"; | ||
import {LibVerifyTrusted} from "./libs/proofTypes/LibVerifyTrusted.sol"; | ||
import {LibVerifyZKP} from "./libs/proofTypes/LibVerifyZKP.sol"; | ||
|
||
library TaikoProofToggleMask { | ||
function getToggleMask() internal pure returns (uint16) { | ||
// BITMAP for efficient iteration and flexible additions later | ||
// ZKP_ONLY, // 0000 0001 | ||
// SGX_ONLY, // 0000 0010 | ||
// RESERVED_X_ONLY, // 0000 0100 | ||
// RESERVED_Y_ONLY, // 0000 1000 | ||
// ZKP_AND_SGX, // 0000 0011 | ||
// X_ZKP_SGX, // 0000 0111 | ||
return uint16(1); // ZKP ONLY by default | ||
} | ||
} | ||
|
||
/// @custom:security-contact [email protected] | ||
contract ProofVerifier is TaikoErrors { | ||
uint256[50] private __gap; | ||
|
||
function getToggleMask() public pure virtual returns (uint16) { | ||
return TaikoProofToggleMask.getToggleMask(); | ||
} | ||
|
||
function verifyProofs( | ||
bytes32 instance, | ||
TaikoData.TypedProof[] calldata blockProofs, | ||
AddressResolver resolver | ||
) | ||
external | ||
view | ||
{ | ||
uint16 mask = getToggleMask(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we should simply remove the mask? A verifier just always hard-codes the logic that needs to be followed. If this logic changes, a different verifier contract should be deployed. Well, it is maybe useful for testing still, so this could be the testnet verifier contract or something like that. But on mainnet, probably just want to keep it as simple as possible. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, makes things more difficult with testing (multi prover vs. exisitng ZK only proofs). |
||
for (uint16 i; i < blockProofs.length;) { | ||
TaikoData.TypedProof memory proof = blockProofs[i]; | ||
if (proof.proofType == 0) { | ||
revert L1_INVALID_PROOFTYPE(); | ||
} | ||
|
||
uint16 bitMask = uint16(1 << (proof.proofType - 1)); | ||
if ((mask & bitMask) == 0) { | ||
revert L1_NOT_ENABLED_PROOFTYPE(); | ||
} | ||
|
||
verifyTypedProof(proof, instance, resolver); | ||
mask &= ~bitMask; | ||
|
||
unchecked { | ||
++i; | ||
} | ||
} | ||
|
||
if(mask != 0) { | ||
revert L1_NOT_ALL_REQ_PROOF_VERIFIED(); | ||
} | ||
} | ||
|
||
function verifyTypedProof( | ||
TaikoData.TypedProof memory proof, | ||
bytes32 instance, | ||
AddressResolver resolver | ||
) internal view { | ||
if (proof.proofType == 1) { | ||
// This is the regular ZK proof and required based on the flag | ||
// in config.proofToggleMask | ||
LibVerifyZKP.verifyProof( | ||
resolver, | ||
proof.proof, | ||
instance, | ||
proof.verifierId | ||
); | ||
} else if (proof.proofType == 2) { | ||
// This is the SGX signature proof and required based on the flag | ||
// in config.proofToggleMask | ||
LibVerifyTrusted.verifyProof( | ||
resolver, | ||
proof.proof, | ||
instance, | ||
proof.verifierId | ||
); | ||
} | ||
} | ||
} | ||
|
||
contract ProxiedProofVerifier is Proxied, ProofVerifier {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think of this API? This way we don't have any dependencies and the proof can really be whatever, and proofs don't have to confirm to
TypedProof
which may not always fit.EDIT: Updated to still have the instance separate. I would say not to pass in the AddressResolver, I think addresses accessed by the verifier should not be set on the protocol AddressResolver, they should store their own data.