diff --git a/deploy-config/local.json b/deploy-config/local.json index f1d05276f..a67283831 100644 --- a/deploy-config/local.json +++ b/deploy-config/local.json @@ -24,6 +24,7 @@ "multiproofIntermediateBlockInterval": 10, "multiproofGenesisOutputRoot": "0x0000000000000000000000000000000000000000000000000000000000000001", "nitroEnclaveVerifier": "0x0000000000000000000000000000000000000000", + "nitroValidator": "0x0000000000000000000000000000000000000000", "operatorFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", "operatorFeeVaultRecipient": "0x1CBd3b2770909D4e10f157cABC84C7264073C9Ec", "operatorFeeVaultWithdrawalNetwork": 0, diff --git a/deploy-config/mainnet.json b/deploy-config/mainnet.json index b8c6602fa..1a673ca4f 100644 --- a/deploy-config/mainnet.json +++ b/deploy-config/mainnet.json @@ -26,6 +26,7 @@ "multiproofGenesisOutputRoot": "0x0000000000000000000000000000000000000000000000000000000000000001", "multiproofIntermediateBlockInterval": 30, "nitroEnclaveVerifier": "0x0000000000000000000000000000000000000000", + "nitroValidator": "0x0000000000000000000000000000000000000000", "operatorFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", "operatorFeeVaultRecipient": "0xa3d596EAfaB6B13Ab18D40FaE1A962700C84ADEa", "operatorFeeVaultWithdrawalNetwork": 0, diff --git a/deploy-config/sepolia.json b/deploy-config/sepolia.json index 8a0b8f145..49b9ef6e4 100644 --- a/deploy-config/sepolia.json +++ b/deploy-config/sepolia.json @@ -26,6 +26,7 @@ "multiproofGenesisOutputRoot": "0xbc273d5876d1858ecd5aaf4ce4eaf16c73f0187ca4271b774ed5da7d2254ba79", "multiproofIntermediateBlockInterval": 30, "nitroEnclaveVerifier": "0x77461a6434fFE3435206B19658F33274f3104e07", + "nitroValidator": "0x0000000000000000000000000000000000000000", "operatorFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", "operatorFeeVaultRecipient": "0xfd1D2e729aE8eEe2E146c033bf4400fE75284301", "operatorFeeVaultWithdrawalNetwork": 0, diff --git a/interfaces/L1/proofs/tee/INitroValidator.sol b/interfaces/L1/proofs/tee/INitroValidator.sol new file mode 100644 index 000000000..f70ffd191 --- /dev/null +++ b/interfaces/L1/proofs/tee/INitroValidator.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { CborElement } from "lib/nitro-validator/src/CborDecode.sol"; + +interface INitroValidator { + /// @notice Pointers to fields in a validated Nitro attestation's TBS bytes. + struct Ptrs { + CborElement moduleID; + uint64 timestamp; + CborElement digest; + CborElement[] pcrs; + CborElement cert; + CborElement[] cabundle; + CborElement publicKey; + CborElement userData; + CborElement nonce; + } + + /// @notice Validates a Nitro attestation using offchain inverse hints. + /// @param attestationTbs The COSE Sign1 to-be-signed bytes. + /// @param signature The 96-byte P-384 attestation signature. + /// @param attestationSigHints Offchain inverse hints for the attestation signature. + /// @return ptrs Pointers to the validated attestation fields. + function validateAttestationWithHints( + bytes calldata attestationTbs, + bytes calldata signature, + bytes calldata attestationSigHints + ) + external + returns (Ptrs memory ptrs); +} diff --git a/interfaces/L1/proofs/tee/ITEEProverRegistry.sol b/interfaces/L1/proofs/tee/ITEEProverRegistry.sol index ea38c36ed..d3079306a 100644 --- a/interfaces/L1/proofs/tee/ITEEProverRegistry.sol +++ b/interfaces/L1/proofs/tee/ITEEProverRegistry.sol @@ -2,11 +2,11 @@ pragma solidity ^0.8.0; import { IDisputeGameFactory } from "interfaces/L1/proofs/IDisputeGameFactory.sol"; -import { INitroEnclaveVerifier } from "interfaces/L1/proofs/tee/INitroEnclaveVerifier.sol"; +import { INitroValidator } from "interfaces/L1/proofs/tee/INitroValidator.sol"; import { GameType } from "src/libraries/bridge/Types.sol"; interface ITEEProverRegistry { - function NITRO_VERIFIER() external view returns (INitroEnclaveVerifier); + function NITRO_VALIDATOR() external view returns (INitroValidator); function DISPUTE_GAME_FACTORY() external view returns (IDisputeGameFactory); function gameType() external view returns (GameType); function isRegisteredSigner(address signer) external view returns (bool); @@ -17,7 +17,7 @@ interface ITEEProverRegistry { function setProposer(address proposer, bool isValid) external; function setGameType(GameType gameType_) external; - function registerSigner(bytes calldata output, bytes calldata proofBytes) external; + function registerSigner(bytes calldata attestationTbs, bytes calldata signature, bytes calldata hints) external; function deregisterSigner(address signer) external; function isValidSigner(address signer) external view returns (bool); function getRegisteredSigners() external view returns (address[] memory); diff --git a/scripts/deploy/DeployConfig.s.sol b/scripts/deploy/DeployConfig.s.sol index da53afb09..3c8bf5a70 100644 --- a/scripts/deploy/DeployConfig.s.sol +++ b/scripts/deploy/DeployConfig.s.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.15; -import { Script } from "lib/forge-std/src/Script.sol"; import { console } from "lib/forge-std/src/console.sol"; +import { Script } from "lib/forge-std/src/Script.sol"; import { stdJson } from "lib/forge-std/src/StdJson.sol"; /// @title DeployConfig @@ -15,6 +15,7 @@ contract DeployConfig is Script { address public finalSystemOwner; address public l1FeeVaultRecipient; address public nitroEnclaveVerifier; + address public nitroValidator; address public operatorFeeVaultRecipient; address public p2pSequencerAddress; address public proxyAdminOwner; @@ -71,6 +72,7 @@ contract DeployConfig is Script { finalSystemOwner = _json.readAddress("$.finalSystemOwner"); l1FeeVaultRecipient = _json.readAddress("$.l1FeeVaultRecipient"); nitroEnclaveVerifier = _json.readAddress("$.nitroEnclaveVerifier"); + nitroValidator = _json.readAddress("$.nitroValidator"); operatorFeeVaultRecipient = _json.readAddress("$.operatorFeeVaultRecipient"); p2pSequencerAddress = _json.readAddress("$.p2pSequencerAddress"); proxyAdminOwner = _json.readAddress("$.proxyAdminOwner"); diff --git a/scripts/deploy/SystemDeploy.s.sol b/scripts/deploy/SystemDeploy.s.sol index 074005f8b..8fa4d4791 100644 --- a/scripts/deploy/SystemDeploy.s.sol +++ b/scripts/deploy/SystemDeploy.s.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.15; -import { VmSafe } from "lib/forge-std/src/Vm.sol"; import { console2 as console } from "lib/forge-std/src/console2.sol"; import { Script } from "lib/forge-std/src/Script.sol"; +import { VmSafe } from "lib/forge-std/src/Vm.sol"; import { Artifacts } from "scripts/Artifacts.s.sol"; import { Config } from "scripts/libraries/Config.sol"; @@ -27,6 +27,8 @@ import { IDelayedWETH } from "interfaces/L1/proofs/IDelayedWETH.sol"; import { IDisputeGame } from "interfaces/L1/proofs/IDisputeGame.sol"; import { IDisputeGameFactory } from "interfaces/L1/proofs/IDisputeGameFactory.sol"; import { IVerifier } from "interfaces/L1/proofs/IVerifier.sol"; +import { INitroEnclaveVerifier } from "interfaces/L1/proofs/tee/INitroEnclaveVerifier.sol"; +import { INitroValidator } from "interfaces/L1/proofs/tee/INitroValidator.sol"; import { ITEEProverRegistry } from "interfaces/L1/proofs/tee/ITEEProverRegistry.sol"; import { IOptimismMintableERC20Factory } from "interfaces/universal/IOptimismMintableERC20Factory.sol"; import { IProxy } from "interfaces/universal/IProxy.sol"; @@ -36,7 +38,6 @@ import { AddressManager } from "src/legacy/AddressManager.sol"; import { AggregateVerifier } from "src/L1/proofs/AggregateVerifier.sol"; import { TEEProverRegistry } from "src/L1/proofs/tee/TEEProverRegistry.sol"; import { TEEVerifier } from "src/L1/proofs/tee/TEEVerifier.sol"; -import { INitroEnclaveVerifier } from "interfaces/L1/proofs/tee/INitroEnclaveVerifier.sol"; import { ISP1Verifier } from "interfaces/L1/proofs/zk/ISP1Verifier.sol"; import { ZKVerifier } from "src/L1/proofs/zk/ZKVerifier.sol"; import { Constants } from "src/libraries/Constants.sol"; @@ -78,6 +79,7 @@ contract SystemDeploy is Script { bytes32 multiproofConfigHash; uint256 multiproofGameType; address nitroEnclaveVerifier; + address nitroValidator; AggregateVerifier.ScheduleConfig scheduleConfig; uint256 multiproofBlockInterval; uint256 multiproofIntermediateBlockInterval; @@ -266,6 +268,7 @@ contract SystemDeploy is Script { multiproofConfigHash: cfg.multiproofConfigHash(), multiproofGameType: cfg.multiproofGameType(), nitroEnclaveVerifier: cfg.nitroEnclaveVerifier(), + nitroValidator: cfg.nitroValidator(), scheduleConfig: _configuredScheduleConfig(), multiproofBlockInterval: cfg.multiproofBlockInterval(), multiproofIntermediateBlockInterval: cfg.multiproofIntermediateBlockInterval(), @@ -564,6 +567,7 @@ contract SystemDeploy is Script { output_.zkVerifier = multiproof.zkVerifier; output_.nitroEnclaveVerifier = INitroEnclaveVerifier(_implementationsInput.nitroEnclaveVerifier); output_.sp1Verifier = _implementationsInput.sp1Verifier; + output_.nitroValidator = INitroValidator(_implementationsInput.nitroValidator); } _transferOwnership(address(output_.disputeGameFactoryProxy), _input.roles.opChainProxyAdminOwner); @@ -709,6 +713,11 @@ contract SystemDeploy is Script { if (address(currentGameImpl) == address(0)) return; if (_impls.teeProverRegistryImpl != address(0)) { + TEEProverRegistry newTEEProverRegistry = TEEProverRegistry(_impls.teeProverRegistryImpl); + require( + address(newTEEProverRegistry.DISPUTE_GAME_FACTORY()) == address(_disputeGameFactory), + "SystemDeploy: TEEProverRegistry factory mismatch" + ); AggregateVerifier currentAggregateVerifier = AggregateVerifier(address(currentGameImpl)); TEEProverRegistry teeProverRegistry = TEEVerifier(address(currentAggregateVerifier.TEE_VERIFIER())).TEE_PROVER_REGISTRY(); @@ -993,9 +1002,9 @@ contract SystemDeploy is Script { GameType gameType = GameType.wrap(uint32(_input.multiproofGameType)); vm.broadcast(msg.sender); - output_.teeProverRegistryImpl = new TEEProverRegistry( - INitroEnclaveVerifier(_input.nitroEnclaveVerifier), _output.disputeGameFactoryProxy - ); + output_.teeProverRegistryImpl = new TEEProverRegistry({ + nitroValidator: INitroValidator(_input.nitroValidator), factory: _output.disputeGameFactoryProxy + }); output_.teeProverRegistryProxy = TEEProverRegistry(_deployProxy(_opChainInput, _output.opChainProxyAdmin, "TEEProverRegistry")); @@ -1017,12 +1026,6 @@ contract SystemDeploy is Script { ) ); - INitroEnclaveVerifier nitroVerifier = INitroEnclaveVerifier(_input.nitroEnclaveVerifier); - if (nitroVerifier.proofSubmitter() != address(output_.teeProverRegistryProxy)) { - vm.broadcast(msg.sender); - nitroVerifier.setProofSubmitter(address(output_.teeProverRegistryProxy)); - } - vm.broadcast(msg.sender); output_.teeVerifier = IVerifier(address(new TEEVerifier(output_.teeProverRegistryProxy, _output.anchorStateRegistryProxy))); @@ -1112,8 +1115,10 @@ contract SystemDeploy is Script { require(_input.scheduleConfig.blockTime != 0, "SystemDeploy: L2 block time not set"); require(_input.scheduleConfig.genesisTimestamp != 0, "SystemDeploy: L2 genesis timestamp not set"); require(_input.nitroEnclaveVerifier != address(0), "SystemDeploy: nitroEnclaveVerifier not set"); + require(_input.nitroValidator != address(0), "SystemDeploy: nitroValidator not set"); require(address(_input.sp1Verifier) != address(0), "SystemDeploy: sp1Verifier not set"); DeployUtils.assertValidContractAddress(_input.nitroEnclaveVerifier); + DeployUtils.assertValidContractAddress(_input.nitroValidator); DeployUtils.assertValidContractAddress(address(_input.sp1Verifier)); require(_input.multiproofBlockInterval != 0, "SystemDeploy: multiproof block interval not set"); require( @@ -1140,6 +1145,11 @@ contract SystemDeploy is Script { DeployUtils.assertValidContractAddress(_impls.anchorStateRegistryImpl); DeployUtils.assertValidContractAddress(_impls.delayedWETHImpl); DeployUtils.assertValidContractAddress(_impls.protocolVersionsImpl); + if (_impls.teeProverRegistryImpl != address(0)) { + TEEProverRegistry teeProverRegistryImpl = TEEProverRegistry(_impls.teeProverRegistryImpl); + DeployUtils.assertValidContractAddress(address(teeProverRegistryImpl)); + DeployUtils.assertValidContractAddress(address(teeProverRegistryImpl.NITRO_VALIDATOR())); + } } function _implementationsEmpty(Types.Implementations memory _impls) internal pure returns (bool) { @@ -1170,6 +1180,7 @@ contract SystemDeploy is Script { _saveIfSet("TEEProverRegistryProxy", address(chain.teeProverRegistryProxy)); _saveIfSet("TEEProverRegistry", address(chain.teeProverRegistryProxy)); _saveIfSet("NitroEnclaveVerifier", address(chain.nitroEnclaveVerifier)); + _saveIfSet("NitroValidator", address(chain.nitroValidator)); _saveIfSet("SP1Verifier", address(chain.sp1Verifier)); } diff --git a/scripts/libraries/Types.sol b/scripts/libraries/Types.sol index 941784952..aea2f0374 100644 --- a/scripts/libraries/Types.sol +++ b/scripts/libraries/Types.sol @@ -5,6 +5,7 @@ import { IDelayedWETH } from "interfaces/L1/proofs/IDelayedWETH.sol"; import { IAnchorStateRegistry } from "interfaces/L1/proofs/IAnchorStateRegistry.sol"; import { IVerifier } from "interfaces/L1/proofs/IVerifier.sol"; import { INitroEnclaveVerifier } from "interfaces/L1/proofs/tee/INitroEnclaveVerifier.sol"; +import { INitroValidator } from "interfaces/L1/proofs/tee/INitroValidator.sol"; import { ITEEProverRegistry } from "interfaces/L1/proofs/tee/ITEEProverRegistry.sol"; import { ISP1Verifier } from "interfaces/L1/proofs/zk/ISP1Verifier.sol"; import { IAddressManager } from "interfaces/legacy/IAddressManager.sol"; @@ -62,6 +63,7 @@ library Types { IVerifier zkVerifier; INitroEnclaveVerifier nitroEnclaveVerifier; ISP1Verifier sp1Verifier; + INitroValidator nitroValidator; } /// @notice The latest implementation contracts for the OP Stack. diff --git a/scripts/multiproof/DeployDevNoNitro.s.sol b/scripts/multiproof/DeployDevNoNitro.s.sol index 83264f695..aa6855cb0 100644 --- a/scripts/multiproof/DeployDevNoNitro.s.sol +++ b/scripts/multiproof/DeployDevNoNitro.s.sol @@ -3,8 +3,8 @@ pragma solidity 0.8.15; import { console2 as console } from "lib/forge-std/src/console2.sol"; -import { INitroEnclaveVerifier } from "interfaces/L1/proofs/tee/INitroEnclaveVerifier.sol"; import { IDisputeGameFactory } from "interfaces/L1/proofs/IDisputeGameFactory.sol"; +import { INitroValidator } from "interfaces/L1/proofs/tee/INitroValidator.sol"; import { DevTEEProverRegistry } from "test/mocks/MockDevTEEProverRegistry.sol"; import { DeployDevBase } from "./DeployDevBase.s.sol"; @@ -34,10 +34,11 @@ contract DeployDevNoNitro is DeployDevBase { } function _deployTEERegistryImpl() internal override returns (address) { - return - address( - new DevTEEProverRegistry(INitroEnclaveVerifier(address(0)), IDisputeGameFactory(disputeGameFactory)) - ); + return address( + new DevTEEProverRegistry({ + nitroValidator: INitroValidator(address(0)), factory: IDisputeGameFactory(disputeGameFactory) + }) + ); } function _logHeader() internal view override { diff --git a/scripts/multiproof/DeployDevWithNitro.s.sol b/scripts/multiproof/DeployDevWithNitro.s.sol index 6fa19f0a6..ed7a777a3 100644 --- a/scripts/multiproof/DeployDevWithNitro.s.sol +++ b/scripts/multiproof/DeployDevWithNitro.s.sol @@ -3,27 +3,26 @@ pragma solidity 0.8.15; import { console2 as console } from "lib/forge-std/src/console2.sol"; -import { INitroEnclaveVerifier } from "interfaces/L1/proofs/tee/INitroEnclaveVerifier.sol"; import { IDisputeGameFactory } from "interfaces/L1/proofs/IDisputeGameFactory.sol"; +import { INitroValidator } from "interfaces/L1/proofs/tee/INitroValidator.sol"; import { TEEProverRegistry } from "src/L1/proofs/tee/TEEProverRegistry.sol"; import { DeployDevBase } from "./DeployDevBase.s.sol"; /// @title DeployDevWithNitro /// @notice Development deployment WITH AWS Nitro attestation validation. Uses the real -/// TEEProverRegistry, so signer registration requires a ZK proof of a valid AWS -/// Nitro attestation (no addDevSigner bypass). -/// @dev Prerequisite: deploy the RISC Zero verifier stack and NitroEnclaveVerifier via -/// DeployRiscZeroStack.s.sol first (those contracts need Solidity ^0.8.20, while this -/// script is pinned to =0.8.15), then set `nitroEnclaveVerifier` in the deploy config. -/// Note: AWS Nitro attestations are only valid for 60 minutes — generate the ZK proof -/// and submit registerSigner() within that window. +/// TEEProverRegistry, so signer registration requires a hinted AWS Nitro attestation +/// (no addDevSigner bypass). +/// @dev Prerequisite: deploy the hinted validator stack via DeployNitroValidatorStack.s.sol, +/// then set `nitroValidator` in the deploy config. AWS Nitro attestations are only valid +/// for 60 minutes, and the certificate chain must be cached before registerSigner() is called. contract DeployDevWithNitro is DeployDevBase { uint256 public constant BLOCK_INTERVAL = 600; uint256 public constant INTERMEDIATE_BLOCK_INTERVAL = 30; uint256 public constant INIT_BOND = 0.00001 ether; address public nitroEnclaveVerifierAddr; + address public nitroValidatorAddr; function _blockInterval() internal pure override returns (uint256) { return BLOCK_INTERVAL; @@ -44,22 +43,24 @@ contract DeployDevWithNitro is DeployDevBase { function _preflight() internal override { super._preflight(); nitroEnclaveVerifierAddr = cfg.nitroEnclaveVerifier(); + nitroValidatorAddr = cfg.nitroValidator(); require( - nitroEnclaveVerifierAddr != address(0), - "nitroEnclaveVerifier must be set in config (deploy via DeployRiscZeroStack.s.sol first)" + nitroValidatorAddr != address(0), + "nitroValidator must be set in config (deploy via DeployNitroValidatorStack.s.sol first)" ); } function _deployTEERegistryImpl() internal override returns (address) { return address( - new TEEProverRegistry( - INitroEnclaveVerifier(nitroEnclaveVerifierAddr), IDisputeGameFactory(disputeGameFactory) - ) + new TEEProverRegistry({ + nitroValidator: INitroValidator(nitroValidatorAddr), factory: IDisputeGameFactory(disputeGameFactory) + }) ); } function _serializeExtra(string memory key) internal override { vm.serializeAddress(key, "NitroEnclaveVerifier", nitroEnclaveVerifierAddr); + vm.serializeAddress(key, "NitroValidator", nitroValidatorAddr); } function _logHeader() internal view override { @@ -69,9 +70,10 @@ contract DeployDevWithNitro is DeployDevBase { console.log("TEE Proposer:", cfg.teeProposer()); console.log("TEE Challenger:", cfg.teeChallenger()); console.log("Game Type:", cfg.multiproofGameType()); - console.log("NitroEnclaveVerifier:", nitroEnclaveVerifierAddr); + console.log("NitroValidator:", nitroValidatorAddr); + console.log("NitroEnclaveVerifier (rollback):", nitroEnclaveVerifierAddr); console.log(""); - console.log("NOTE: Using REAL TEEProverRegistry - ZK attestation proof REQUIRED."); + console.log("NOTE: Using REAL TEEProverRegistry - hinted attestation REQUIRED."); } function _printSummary() internal view override { @@ -79,7 +81,8 @@ contract DeployDevWithNitro is DeployDevBase { console.log(" DEV DEPLOYMENT COMPLETE (WITH NITRO)"); console.log("========================================"); console.log("\nTEE Contracts:"); - console.log(" NitroEnclaveVerifier:", nitroEnclaveVerifierAddr); + console.log(" NitroValidator:", nitroValidatorAddr); + console.log(" NitroEnclaveVerifier (rollback):", nitroEnclaveVerifierAddr); console.log(" TEEProverRegistry:", teeProverRegistryProxy); console.log(" TEEVerifier:", teeVerifier); console.log("\nInfrastructure:"); @@ -92,9 +95,9 @@ contract DeployDevWithNitro is DeployDevBase { console.log(" TEE Image Hash:", vm.toString(cfg.teeImageHash())); console.log(" Config Hash:", vm.toString(cfg.multiproofConfigHash())); console.log("========================================"); - console.log("\n>>> NEXT STEP: Register signer with ZK attestation proof <<<"); + console.log("\n>>> NEXT STEP: Cache certificates, then register the signer <<<"); console.log("\n cast send", teeProverRegistryProxy); - console.log(' "registerSigner(bytes,bytes)" '); + console.log(' "registerSigner(bytes,bytes,bytes)" '); console.log(" --private-key --rpc-url "); console.log("\n========================================\n"); } diff --git a/scripts/multiproof/DeployRiscZeroStack.s.sol b/scripts/multiproof/DeployRiscZeroStack.s.sol index 42fac5883..46e26b528 100644 --- a/scripts/multiproof/DeployRiscZeroStack.s.sol +++ b/scripts/multiproof/DeployRiscZeroStack.s.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.20; /** * @title DeployRiscZeroStack - * @notice Deploys a RiscZeroSetVerifier and NitroEnclaveVerifier that work with + * @notice Deploys the legacy rollback RiscZeroSetVerifier and NitroEnclaveVerifier that work with * an existing RISC Zero verifier router (e.g. the Boundless-deployed * Router on Sepolia). * @@ -39,9 +39,9 @@ pragma solidity ^0.8.20; * - RiscZeroSetVerifier (delegates to existing Router for root verification) * - NitroEnclaveVerifier with route wired to the local SetVerifier * - * POST-DEPLOY: - * After deploying TEEProverRegistry via DeployDevWithNitro.s.sol, update the - * proofSubmitter on NitroEnclaveVerifier to the TEEProverRegistry address: + * ROLLBACK PREPARATION: + * The hinted TEEProverRegistry does not call this verifier. Before rolling back to the + * legacy Registry implementation, point proofSubmitter at the existing Registry proxy: * * cast send "setProofSubmitter(address)" \ * --rpc-url --private-key @@ -102,8 +102,8 @@ contract DeployRiscZeroStack is Script { console.log("Nitro Root Cert:", vm.toString(nitroRootCert)); console.log("Nitro Verifier ID:", vm.toString(nitroVerifierId)); console.log(""); - console.log("NOTE: proofSubmitter is set to owner as placeholder."); - console.log(" Update it to TEEProverRegistry after deploying via setProofSubmitter()."); + console.log("NOTE: This is the legacy rollback verifier stack."); + console.log(" Set proofSubmitter to the Registry proxy before a legacy rollback."); console.log(""); vm.startBroadcast(); @@ -154,9 +154,8 @@ contract DeployRiscZeroStack is Script { console.log("NitroEnclaveVerifier:", nitroEnclaveVerifier); console.log("RISC Zero Router (external):", risc0VerifierRouter); console.log(""); - console.log(">>> Set nitroEnclaveVerifier in deploy config to:", nitroEnclaveVerifier); - console.log(">>> Then run DeployDevWithNitro.s.sol <<<"); - console.log(">>> Then call setProofSubmitter(TEEProverRegistry) on NitroEnclaveVerifier <<<"); + console.log(">>> Retain NitroEnclaveVerifier for rollback:", nitroEnclaveVerifier); + console.log(">>> The active hinted Registry uses NitroValidator instead <<<"); console.log("========================================"); string memory key = "deployment"; diff --git a/scripts/multiproof/README.md b/scripts/multiproof/README.md index 166f86d16..dcae83a2e 100644 --- a/scripts/multiproof/README.md +++ b/scripts/multiproof/README.md @@ -120,7 +120,38 @@ The deployer address (`finalSystemOwner`) is the owner of `DevTEEProverRegistry` ## Path 2: WithNitro (Dev — Real Attestation) -> **TODO:** Add deployment and registration guide for `DeployDevWithNitro.s.sol`. +Deploy the hinted validator stack, using production-controlled owner and revoker addresses: + +```bash +forge script scripts/multiproof/DeployNitroValidatorStack.s.sol:DeployNitroValidatorStack \ + --sig "run(address,address)" \ + --broadcast --rpc-url --private-key +``` + +Copy the `NitroValidator` address from `deployments/-nitro-validator.json` into the +deploy config's `nitroValidator` field. Keep `nitroEnclaveVerifier` configured separately as a +rollback dependency; the hinted Registry does not call it or update its `proofSubmitter`. + +Run `DeployDevWithNitro.s.sol`. Before registering a signer, pre-cache every non-root CA and the +leaf certificate in the validator's `CertManager`. The dependency's call-plan tool can generate +the ordered certificate calls and hints for development: + +```bash +node lib/nitro-validator/tools/hinted_attestation_calls.js fixture \ + --cert-manager --validator +``` + +After the certificate chain is cached, submit the signed TBS and attestation-signature hints: + +```bash +cast send \ + "registerSigner(bytes,bytes,bytes)" \ + \ + --rpc-url --private-key +``` + +The Registry requires a 48-byte PCR0, a 65-byte `0x04 || x || y` secp256k1 `public_key`, and an +attestation timestamp strictly within the previous 60 minutes. --- diff --git a/snapshots/abi/TEEProverRegistry.json b/snapshots/abi/TEEProverRegistry.json index 510962c5d..de1acd497 100644 --- a/snapshots/abi/TEEProverRegistry.json +++ b/snapshots/abi/TEEProverRegistry.json @@ -2,8 +2,8 @@ { "inputs": [ { - "internalType": "contract INitroEnclaveVerifier", - "name": "nitroVerifier", + "internalType": "contract INitroValidator", + "name": "nitroValidator", "type": "address" }, { @@ -43,10 +43,10 @@ }, { "inputs": [], - "name": "NITRO_VERIFIER", + "name": "NITRO_VALIDATOR", "outputs": [ { - "internalType": "contract INitroEnclaveVerifier", + "internalType": "contract INitroValidator", "name": "", "type": "address" } @@ -221,12 +221,17 @@ "inputs": [ { "internalType": "bytes", - "name": "output", + "name": "attestationTbs", "type": "bytes" }, { "internalType": "bytes", - "name": "proofBytes", + "name": "signature", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "hints", "type": "bytes" } ], @@ -449,12 +454,12 @@ }, { "inputs": [], - "name": "AttestationTooOld", + "name": "AttestationFromFuture", "type": "error" }, { "inputs": [], - "name": "AttestationVerificationFailed", + "name": "AttestationTooOld", "type": "error" }, { @@ -472,6 +477,11 @@ "name": "InvalidGameType", "type": "error" }, + { + "inputs": [], + "name": "InvalidPCR0", + "type": "error" + }, { "inputs": [], "name": "InvalidPublicKey", diff --git a/snapshots/semver-lock.json b/snapshots/semver-lock.json index 9df6df8d0..ab95eaa7e 100644 --- a/snapshots/semver-lock.json +++ b/snapshots/semver-lock.json @@ -48,8 +48,8 @@ "sourceCodeHash": "0x03c164216b27f82ee13064ace6079d5e24e187d888f41bd01c8daffa60c575d6" }, "src/L1/proofs/tee/TEEProverRegistry.sol:TEEProverRegistry": { - "initCodeHash": "0xfd1942e1c2f59b0aa72b33d698a948a53b6e4cf1040106f173fb5d89f63f57b0", - "sourceCodeHash": "0x7dc91bb80f476c50d3e1e39fc29316a216dd03eebe25b79c936a5a3d2f595489" + "initCodeHash": "0xef50e4cd4734c5a7137c9071334fc159a36869744ec2fa25d320c172999c4b3b", + "sourceCodeHash": "0xd7aef97975588bb749c24b69f83055f329da06ce1b6b7634e51d0080557fb98e" }, "src/L1/proofs/tee/TEEVerifier.sol:TEEVerifier": { "initCodeHash": "0x655576cc21cc5c603d55fb4dd2a2f0ef57b11deeaabd3e539b0a70a5f7e2c9af", diff --git a/src/L1/proofs/tee/TEEProverRegistry.sol b/src/L1/proofs/tee/TEEProverRegistry.sol index 84d64efc5..e708a081a 100644 --- a/src/L1/proofs/tee/TEEProverRegistry.sol +++ b/src/L1/proofs/tee/TEEProverRegistry.sol @@ -1,30 +1,28 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.15; -import { - INitroEnclaveVerifier, - ZkCoProcessorType, - VerifierJournal, - VerificationResult, - Pcr, - Bytes48 -} from "interfaces/L1/proofs/tee/INitroEnclaveVerifier.sol"; -import { ISemver } from "interfaces/universal/ISemver.sol"; +import { CborDecode, CborElement, LibCborElement } from "lib/nitro-validator/src/CborDecode.sol"; + +import { EnumerableSetLib } from "src/vendor/EnumerableSetLib.sol"; import { IDisputeGameFactory } from "interfaces/L1/proofs/IDisputeGameFactory.sol"; +import { INitroValidator } from "interfaces/L1/proofs/tee/INitroValidator.sol"; +import { ISemver } from "interfaces/universal/ISemver.sol"; import { OwnableManagedUpgradeable } from "src/universal/OwnableManagedUpgradeable.sol"; -import { EnumerableSetLib } from "src/vendor/EnumerableSetLib.sol"; import { GameType } from "src/libraries/bridge/Types.sol"; /// @title TEEProverRegistry -/// @notice Manages TEE signer registration via ZK-verified AWS Nitro attestation. -/// @dev Signers are registered by providing a ZK proof of a valid AWS Nitro attestation document, -/// verified through an external NitroEnclaveVerifier contract (Risc0). +/// @notice Manages TEE signer registration via hinted AWS Nitro attestation validation. +/// @dev Signers are registered by providing an AWS Nitro attestation and P-384 verification hints. +/// The attestation's certificate chain must already be cached in the NitroValidator's CertManager. /// Registration is PCR0-agnostic: any enclave with a valid attestation can register, /// enabling pre-registration before hardforks. PCR0 enforcement happens at proof-submission /// time in TEEVerifier, which checks signerImageHash against the AggregateVerifier's /// TEE_IMAGE_HASH. contract TEEProverRegistry is OwnableManagedUpgradeable, ISemver { + using CborDecode for bytes; using EnumerableSetLib for EnumerableSetLib.AddressSet; + using LibCborElement for CborElement; + /// @notice Maximum age of an attestation document (60 minutes), in seconds. uint256 public constant MAX_AGE = 60 minutes; @@ -33,8 +31,11 @@ contract TEEProverRegistry is OwnableManagedUpgradeable, ISemver { /// but block.timestamp is in seconds. uint256 private constant MS_PER_SECOND = 1000; - /// @notice The external NitroEnclaveVerifier contract used for ZK attestation verification. - INitroEnclaveVerifier public immutable NITRO_VERIFIER; + /// @notice The hash of the all-zero PCR0 emitted by debug-mode Nitro enclaves. + bytes32 private constant DEBUG_MODE_PCR0_HASH = 0xc980e59163ce244bb4bb6211f48c7b46f88a4f40943e84eb99bdc41e129bd293; + + /// @notice The external NitroValidator contract used for hinted attestation validation. + INitroValidator public immutable NITRO_VALIDATOR; /// @notice The DisputeGameFactory used to look up the current AggregateVerifier and its TEE_IMAGE_HASH. IDisputeGameFactory public immutable DISPUTE_GAME_FACTORY; @@ -47,7 +48,7 @@ contract TEEProverRegistry is OwnableManagedUpgradeable, ISemver { mapping(address => bool) public isRegisteredSigner; /// @notice Mapping of signer address to the PCR0 image hash from their attestation. - /// @dev Stored at registration time from the ZK-verified attestation document. + /// @dev Stored at registration time from the validated attestation document. /// TEEVerifier checks this against the AggregateVerifier's TEE_IMAGE_HASH at /// proof-submission time, so signers automatically become unusable when the /// AggregateVerifier upgrades to a new image hash. isValidSigner also uses @@ -77,15 +78,18 @@ contract TEEProverRegistry is OwnableManagedUpgradeable, ISemver { /// @notice Thrown when the attestation document is too old. error AttestationTooOld(); - /// @notice Thrown when the ZK attestation verification fails. - error AttestationVerificationFailed(); + /// @notice Thrown when the attestation document is dated in the future. + error AttestationFromFuture(); - /// @notice Thrown when the attestation's public key is too short to derive a signer address. + /// @notice Thrown when the attestation's public key is not an uncompressed secp256k1 key. error InvalidPublicKey(); /// @notice Thrown when PCR0 (index 0) is not found in the attestation's PCR list. error PCR0NotFound(); + /// @notice Thrown when PCR0 is not a 48-byte SHA-384 measurement. + error InvalidPCR0(); + /// @notice Thrown when the dispute game factory is not configured. error DisputeGameFactoryNotSet(); @@ -95,9 +99,9 @@ contract TEEProverRegistry is OwnableManagedUpgradeable, ISemver { /// @notice Thrown when setting a game type whose AggregateVerifier has no TEE_IMAGE_HASH. error InvalidGameType(); - constructor(INitroEnclaveVerifier nitroVerifier, IDisputeGameFactory factory) { + constructor(INitroValidator nitroValidator, IDisputeGameFactory factory) { if (address(factory) == address(0)) revert DisputeGameFactoryNotSet(); - NITRO_VERIFIER = nitroVerifier; + NITRO_VALIDATOR = nitroValidator; DISPUTE_GAME_FACTORY = factory; initialize({ initialOwner: address(0xdEaD), @@ -130,9 +134,9 @@ contract TEEProverRegistry is OwnableManagedUpgradeable, ISemver { emit GameTypeUpdated(gameType_); } - /// @notice Registers a signer using a ZK proof of an AWS Nitro attestation document. - /// @dev The ZK proof must verify a valid attestation that: - /// 1. Has a valid AWS Nitro certificate chain (verified offchain via ZK) + /// @notice Registers a signer using a hinted AWS Nitro attestation document. + /// @dev The NitroValidator must verify an attestation that: + /// 1. Has a valid, pre-cached AWS Nitro certificate chain /// 2. Is less than MAX_AGE old /// Registration is PCR0-agnostic: any enclave with a valid attestation can register. /// This enables pre-registration of new-PCR0 enclaves before a hardfork, eliminating @@ -140,26 +144,37 @@ contract TEEProverRegistry is OwnableManagedUpgradeable, ISemver { /// enforces PCR0 correctness at proof-submission time by checking signerImageHash /// against the AggregateVerifier's TEE_IMAGE_HASH, so pre-registered enclaves cannot /// produce accepted proofs until the hardfork activates. - /// @param output The ABI-encoded VerifierJournal from the ZK proof. - /// @param proofBytes The Risc0 ZK proof bytes. - function registerSigner(bytes calldata output, bytes calldata proofBytes) external onlyOwnerOrManager { - VerifierJournal memory journal = NITRO_VERIFIER.verify(output, ZkCoProcessorType.RiscZero, proofBytes); - - if (journal.result != VerificationResult.Success) revert AttestationVerificationFailed(); + /// @param attestationTbs The COSE Sign1 to-be-signed bytes. + /// @param signature The 96-byte P-384 attestation signature. + /// @param hints Offchain inverse hints for the attestation signature. + function registerSigner( + bytes calldata attestationTbs, + bytes calldata signature, + bytes calldata hints + ) + external + onlyOwnerOrManager + { + // The validator returns offsets into the TBS; copy it once for the memory-only CBOR helpers below. + bytes memory tbs = attestationTbs; + INitroValidator.Ptrs memory ptrs = NITRO_VALIDATOR.validateAttestationWithHints(tbs, signature, hints); - // We allow attestations up to MAX_AGE old. This means a cert may be expired between when - // the attestation is generated and when it is submitted to this contract. - if (journal.timestamp / MS_PER_SECOND + MAX_AGE <= block.timestamp) revert AttestationTooOld(); + uint256 attestationTimestamp = ptrs.timestamp / MS_PER_SECOND; + if (attestationTimestamp + MAX_AGE <= block.timestamp) revert AttestationTooOld(); + if (attestationTimestamp >= block.timestamp) revert AttestationFromFuture(); // Extract the attestation's PCR0 and store it for TEEVerifier to check at // proof-submission time. No comparison against the current TEE_IMAGE_HASH // here — the registry accepts any valid attestation. - bytes32 pcr0Hash = _extractPCR0Hash(journal.pcrs); + if (ptrs.pcrs.length == 0 || ptrs.pcrs[0].isNull()) revert PCR0NotFound(); + if (ptrs.pcrs[0].length() != 48) revert InvalidPCR0(); + bytes32 pcr0Hash = tbs.keccak(ptrs.pcrs[0]); + if (pcr0Hash == DEBUG_MODE_PCR0_HASH) revert InvalidPCR0(); // The publicKey is encoded in ANSI X9.62 format: 0x04 || x || y (65 bytes). // We skip the first byte (0x04 prefix) when hashing to derive the address. - bytes memory pubKey = journal.publicKey; - if (pubKey.length != 65) revert InvalidPublicKey(); + bytes memory pubKey = tbs.slice(ptrs.publicKey); + if (pubKey.length != 65 || pubKey[0] != 0x04) revert InvalidPublicKey(); bytes32 publicKeyHash; assembly { // Length is hardcoded to 64 to skip the 0x04 prefix and hash only the x and y coordinates @@ -233,9 +248,9 @@ contract TEEProverRegistry is OwnableManagedUpgradeable, ISemver { } /// @notice Semantic version. - /// @custom:semver 0.5.0 + /// @custom:semver 0.6.0 function version() public pure virtual returns (string memory) { - return "0.5.0"; + return "0.6.0"; } /// @dev Reads TEE_IMAGE_HASH from the AggregateVerifier registered in the factory. @@ -246,15 +261,4 @@ contract TEEProverRegistry is OwnableManagedUpgradeable, ISemver { if (!success || data.length != 32) revert ImageHashReadFailed(); return abi.decode(data, (bytes32)); } - - /// @dev Finds PCR0 (index 0) in the PCR array and returns its keccak256 hash. - function _extractPCR0Hash(Pcr[] memory pcrs) internal pure returns (bytes32) { - for (uint256 i = 0; i < pcrs.length; i++) { - if (pcrs[i].index == 0) { - Bytes48 memory value = pcrs[i].value; - return keccak256(abi.encodePacked(value.first, value.second)); - } - } - revert PCR0NotFound(); - } } diff --git a/test/L1/proofs/TEEProverRegistry.t.sol b/test/L1/proofs/TEEProverRegistry.t.sol index 079f4635f..a067c4a4a 100644 --- a/test/L1/proofs/TEEProverRegistry.t.sol +++ b/test/L1/proofs/TEEProverRegistry.t.sol @@ -1,17 +1,23 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.15; +import { CborDecode, CborElement, LibCborElement } from "lib/nitro-validator/src/CborDecode.sol"; +import { ICertManager } from "lib/nitro-validator/src/ICertManager.sol"; +import { IP384Verifier } from "lib/nitro-validator/src/IP384Verifier.sol"; +import { NitroValidator } from "lib/nitro-validator/src/NitroValidator.sol"; +import { Sha2Ext } from "lib/nitro-validator/src/Sha2Ext.sol"; import { Test } from "lib/forge-std/src/Test.sol"; import { Proxy } from "src/universal/Proxy.sol"; -import { INitroEnclaveVerifier } from "interfaces/L1/proofs/tee/INitroEnclaveVerifier.sol"; import { IDisputeGameFactory } from "interfaces/L1/proofs/IDisputeGameFactory.sol"; +import { INitroValidator } from "interfaces/L1/proofs/tee/INitroValidator.sol"; import { GameType } from "src/libraries/bridge/Types.sol"; import { IDisputeGame } from "interfaces/L1/proofs/IDisputeGame.sol"; import { DevTEEProverRegistry } from "test/mocks/MockDevTEEProverRegistry.sol"; +import { MockNitroValidator } from "test/mocks/MockNitroValidator.sol"; import { TEEProverRegistry } from "src/L1/proofs/tee/TEEProverRegistry.sol"; contract MockAggregateVerifierForRegistry { @@ -34,12 +40,21 @@ contract MockDisputeGameFactoryForRegistry { } } +contract NitroValidatorParseHarnessForRegistry is NitroValidator { + constructor(ICertManager certManager, IP384Verifier p384Verifier) NitroValidator(certManager, p384Verifier) { } + + function parseAttestation(bytes memory attestationTbs) external pure returns (Ptrs memory) { + return _parseAttestation(attestationTbs); + } +} + /// @dev Uses DevTEEProverRegistry because production signer registration requires a Nitro attestation proof. contract TEEProverRegistryTest is Test { DevTEEProverRegistry public teeProverRegistry; address public owner; address public manager; + address public proxyAdmin; address public unauthorized; bytes32 public constant TEST_IMAGE_HASH = keccak256("test-image-hash"); @@ -65,10 +80,11 @@ contract TEEProverRegistryTest is Test { MockAggregateVerifierForRegistry verifier = new MockAggregateVerifierForRegistry(TEST_IMAGE_HASH); MockDisputeGameFactoryForRegistry factory = new MockDisputeGameFactoryForRegistry(address(verifier)); - DevTEEProverRegistry impl = - new DevTEEProverRegistry(INitroEnclaveVerifier(address(0)), IDisputeGameFactory(address(factory))); + DevTEEProverRegistry impl = new DevTEEProverRegistry({ + nitroValidator: INitroValidator(address(0)), factory: IDisputeGameFactory(address(factory)) + }); - address proxyAdmin = makeAddr("proxy-admin"); + proxyAdmin = makeAddr("proxy-admin"); Proxy proxy = new Proxy(proxyAdmin); vm.prank(proxyAdmin); proxy.upgradeToAndCall( @@ -112,7 +128,7 @@ contract TEEProverRegistryTest is Test { function testInitialization() public view { assertEq(teeProverRegistry.owner(), owner); assertEq(teeProverRegistry.manager(), manager); - assertEq(teeProverRegistry.version(), "0.5.0"); + assertEq(teeProverRegistry.version(), "0.6.0"); } function testInitializationWithProposers() public { @@ -395,4 +411,379 @@ contract TEEProverRegistryTest is Test { assertEq(teeProverRegistry.getRegisteredSigners().length, 0); } + + function test_upgrade_preservesStorage_succeeds() public { + address signer = makeAddr("upgrade-signer"); + address proposer = makeAddr("upgrade-proposer"); + _addDevSigner(signer); + vm.prank(owner); + teeProverRegistry.setProposer(proposer, true); + + MockNitroValidator nitroValidator = new MockNitroValidator(); + TEEProverRegistry newImpl = new TEEProverRegistry({ + nitroValidator: INitroValidator(address(nitroValidator)), factory: teeProverRegistry.DISPUTE_GAME_FACTORY() + }); + + vm.prank(proxyAdmin); + Proxy(payable(address(teeProverRegistry))).upgradeTo(address(newImpl)); + + TEEProverRegistry upgraded = TEEProverRegistry(address(teeProverRegistry)); + assertEq(upgraded.owner(), owner); + assertEq(upgraded.manager(), manager); + assertEq(GameType.unwrap(upgraded.gameType()), GameType.unwrap(TEST_GAME_TYPE)); + assertTrue(upgraded.isValidProposer(proposer)); + assertTrue(upgraded.isRegisteredSigner(signer)); + assertEq(upgraded.signerImageHash(signer), TEST_IMAGE_HASH); + assertEq(upgraded.getRegisteredSigners().length, 1); + assertEq(upgraded.getRegisteredSigners()[0], signer); + assertEq(address(upgraded.NITRO_VALIDATOR()), address(nitroValidator)); + } +} + +contract TEEProverRegistry_RegisterSigner_Test is Test { + using CborDecode for bytes; + + uint256 internal constant EIP_7825_GAS_CAP = 16_777_216; + uint256 internal constant REAL_ATTESTATION_TIMESTAMP = 1_767_472_867; + uint256 internal constant SIGNER_PRIVATE_KEY = 0x1234567890abcdef; + GameType internal constant TEST_GAME_TYPE = GameType.wrap(621); + bytes internal constant SIGNATURE = hex"0102"; + bytes internal constant HINTS = hex"0304"; + + struct Fixture { + bytes tbs; + bytes signature; + bytes hints; + } + + TEEProverRegistry internal teeProverRegistry; + MockNitroValidator internal mockNitroValidator; + address internal owner; + address internal manager; + address internal signer; + bytes32 internal pcr0Hash; + bytes internal attestationTbs; + ICertManager internal certManager; + IP384Verifier internal p384Verifier; + NitroValidator internal nitroValidator; + NitroValidatorParseHarnessForRegistry internal parser; + + event SignerRegistered(address indexed signer); + + function setUp() public { + owner = makeAddr("owner"); + manager = makeAddr("manager"); + signer = vm.addr(SIGNER_PRIVATE_KEY); + + bytes memory pcr0 = + hex"0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30"; + pcr0Hash = keccak256(pcr0); + + bytes memory publicKey = + hex"04f973a0b87062c389d125d8199e803b832b6ac6bf7867a4f6cd87506060fc4c584b4a0a3f26c988c54c236b224c48bb605b265949e65c098ecd87a581ca10e25d"; + attestationTbs = abi.encodePacked(pcr0, publicKey); + + mockNitroValidator = new MockNitroValidator(); + MockAggregateVerifierForRegistry verifier = new MockAggregateVerifierForRegistry(pcr0Hash); + MockDisputeGameFactoryForRegistry factory = new MockDisputeGameFactoryForRegistry(address(verifier)); + TEEProverRegistry impl = new TEEProverRegistry({ + nitroValidator: INitroValidator(address(mockNitroValidator)), factory: IDisputeGameFactory(address(factory)) + }); + + address proxyAdmin = makeAddr("proxy-admin"); + Proxy proxy = new Proxy(proxyAdmin); + vm.prank(proxyAdmin); + proxy.upgradeToAndCall( + address(impl), + abi.encodeCall(TEEProverRegistry.initialize, (owner, manager, new address[](0), TEST_GAME_TYPE)) + ); + teeProverRegistry = TEEProverRegistry(address(proxy)); + + vm.warp(10_000); + } + + function test_registerSigner_owner_succeeds() public { + _mockValidation(_validPtrs(uint64((block.timestamp - 1) * 1000))); + + vm.expectEmit(true, false, false, false, address(teeProverRegistry)); + emit SignerRegistered(signer); + vm.prank(owner); + teeProverRegistry.registerSigner(attestationTbs, SIGNATURE, HINTS); + + assertTrue(teeProverRegistry.isRegisteredSigner(signer)); + assertTrue(teeProverRegistry.isValidSigner(signer)); + assertEq(teeProverRegistry.signerImageHash(signer), pcr0Hash); + assertEq(teeProverRegistry.getRegisteredSigners().length, 1); + assertEq(teeProverRegistry.getRegisteredSigners()[0], signer); + } + + function test_registerSigner_manager_succeeds() public { + _mockValidation(_validPtrs(uint64((block.timestamp - 1) * 1000))); + + vm.prank(manager); + teeProverRegistry.registerSigner(attestationTbs, SIGNATURE, HINTS); + + assertTrue(teeProverRegistry.isRegisteredSigner(signer)); + } + + function test_registerSigner_unauthorized_reverts() public { + vm.prank(makeAddr("unauthorized")); + vm.expectRevert("OwnableManaged: caller is not the owner or the manager"); + teeProverRegistry.registerSigner(attestationTbs, SIGNATURE, HINTS); + } + + function test_registerSigner_validatorFailure_reverts() public { + bytes memory callData = _validatorCall(); + vm.mockCallRevert( + address(mockNitroValidator), callData, abi.encodeWithSignature("Error(string)", "unused inverse hints") + ); + + vm.prank(owner); + vm.expectRevert("unused inverse hints"); + teeProverRegistry.registerSigner(attestationTbs, SIGNATURE, HINTS); + } + + function test_registerSigner_attestationAtMaxAge_reverts() public { + _mockValidation(_validPtrs(uint64((block.timestamp - teeProverRegistry.MAX_AGE()) * 1000))); + + vm.prank(owner); + vm.expectRevert(TEEProverRegistry.AttestationTooOld.selector); + teeProverRegistry.registerSigner(attestationTbs, SIGNATURE, HINTS); + } + + function test_registerSigner_attestationOneSecondInsideMaxAge_succeeds() public { + _mockValidation(_validPtrs(uint64((block.timestamp - teeProverRegistry.MAX_AGE() + 1) * 1000))); + + vm.prank(owner); + teeProverRegistry.registerSigner(attestationTbs, SIGNATURE, HINTS); + + assertTrue(teeProverRegistry.isRegisteredSigner(signer)); + } + + function test_registerSigner_currentTimestamp_reverts() public { + _mockValidation(_validPtrs(uint64(block.timestamp * 1000))); + + vm.prank(owner); + vm.expectRevert(TEEProverRegistry.AttestationFromFuture.selector); + teeProverRegistry.registerSigner(attestationTbs, SIGNATURE, HINTS); + } + + function test_registerSigner_futureTimestamp_reverts() public { + _mockValidation(_validPtrs(uint64((block.timestamp + 1) * 1000))); + + vm.prank(owner); + vm.expectRevert(TEEProverRegistry.AttestationFromFuture.selector); + teeProverRegistry.registerSigner(attestationTbs, SIGNATURE, HINTS); + } + + function test_registerSigner_missingPCR0_reverts() public { + INitroValidator.Ptrs memory ptrs = _validPtrs(uint64((block.timestamp - 1) * 1000)); + ptrs.pcrs[0] = LibCborElement.toCborElement(0xf6, 0, 0); + _mockValidation(ptrs); + + vm.prank(owner); + vm.expectRevert(TEEProverRegistry.PCR0NotFound.selector); + teeProverRegistry.registerSigner(attestationTbs, SIGNATURE, HINTS); + } + + function test_registerSigner_debugModePCR0_reverts() public { + for (uint256 i = 0; i < 48; i++) { + attestationTbs[i] = 0; + } + _mockValidation(_validPtrs(uint64((block.timestamp - 1) * 1000))); + + vm.prank(owner); + vm.expectRevert(TEEProverRegistry.InvalidPCR0.selector); + teeProverRegistry.registerSigner(attestationTbs, SIGNATURE, HINTS); + } + + function testFuzz_registerSigner_invalidPCR0Length_reverts(uint8 pcr0Length) public { + vm.assume(pcr0Length != 48); + INitroValidator.Ptrs memory ptrs = _validPtrs(uint64((block.timestamp - 1) * 1000)); + ptrs.pcrs[0] = LibCborElement.toCborElement(0x40, 0, pcr0Length); + _mockValidation(ptrs); + + vm.prank(owner); + vm.expectRevert(TEEProverRegistry.InvalidPCR0.selector); + teeProverRegistry.registerSigner(attestationTbs, SIGNATURE, HINTS); + } + + function test_registerSigner_invalidPublicKeyLength_reverts() public { + INitroValidator.Ptrs memory ptrs = _validPtrs(uint64((block.timestamp - 1) * 1000)); + ptrs.publicKey = LibCborElement.toCborElement(0x40, 48, 64); + _mockValidation(ptrs); + + vm.prank(owner); + vm.expectRevert(TEEProverRegistry.InvalidPublicKey.selector); + teeProverRegistry.registerSigner(attestationTbs, SIGNATURE, HINTS); + } + + function test_registerSigner_invalidPublicKeyPrefix_reverts() public { + attestationTbs[48] = 0x02; + _mockValidation(_validPtrs(uint64((block.timestamp - 1) * 1000))); + + vm.prank(owner); + vm.expectRevert(TEEProverRegistry.InvalidPublicKey.selector); + teeProverRegistry.registerSigner(attestationTbs, SIGNATURE, HINTS); + } + + function _validPtrs(uint64 timestamp) internal pure returns (INitroValidator.Ptrs memory ptrs) { + ptrs.timestamp = timestamp; + ptrs.pcrs = new CborElement[](32); + ptrs.pcrs[0] = LibCborElement.toCborElement(0x40, 0, 48); + ptrs.cabundle = new CborElement[](0); + ptrs.publicKey = LibCborElement.toCborElement(0x40, 48, 65); + } + + function _validatorCall() internal view returns (bytes memory) { + return abi.encodeCall(INitroValidator.validateAttestationWithHints, (attestationTbs, SIGNATURE, HINTS)); + } + + function _mockValidation(INitroValidator.Ptrs memory ptrs) internal { + vm.mockCall(address(mockNitroValidator), _validatorCall(), abi.encode(ptrs)); + } + + function _setUpRealAttestation() internal { + vm.warp(REAL_ATTESTATION_TIMESTAMP + 1); + (p384Verifier, certManager, nitroValidator) = _deployValidatorStack(); + parser = new NitroValidatorParseHarnessForRegistry(certManager, p384Verifier); + teeProverRegistry = _deployRegistry(nitroValidator); + } + + function test_registerSigner_realAttestationWithoutPublicKey_reverts() public { + _setUpRealAttestation(); + Fixture memory fixture = _prepareFixture(); + bytes memory callData = + abi.encodeCall(TEEProverRegistry.registerSigner, (fixture.tbs, fixture.signature, fixture.hints)); + + uint256 gasBefore = gasleft(); + (bool success, bytes memory returndata) = address(teeProverRegistry).call(callData); + uint256 executionGas = gasBefore - gasleft(); + + assertFalse(success); + assertEq(returndata, abi.encodeWithSelector(TEEProverRegistry.InvalidPublicKey.selector)); + assertLt(executionGas + 21_000 + _calldataGas(callData), EIP_7825_GAS_CAP); + } + + function _prepareFixture() internal returns (Fixture memory fixture_) { + bytes memory attestation = _loadRealAttestation(); + (fixture_.tbs, fixture_.signature) = nitroValidator.decodeAttestationTbs(attestation); + NitroValidator.Ptrs memory ptrs = parser.parseAttestation(fixture_.tbs); + + bytes32 parentHash; + for (uint256 i = 0; i < ptrs.cabundle.length; i++) { + bytes memory cert = fixture_.tbs.slice(ptrs.cabundle[i]); + bytes memory certHints; + if (parentHash != bytes32(0)) { + certHints = _collectCertHints(cert, certManager.loadVerified(parentHash).pubKey); + } + parentHash = certManager.verifyCACertWithHints(cert, parentHash, certHints); + } + + bytes memory leafCert = fixture_.tbs.slice(ptrs.cert); + bytes memory leafHints = _collectCertHints(leafCert, certManager.loadVerified(parentHash).pubKey); + ICertManager.VerifiedCert memory leaf = certManager.verifyClientCertWithHints(leafCert, parentHash, leafHints); + fixture_.hints = _collectVerifyHints( + Sha2Ext.sha384(fixture_.tbs, 0, fixture_.tbs.length), fixture_.signature, leaf.pubKey + ); + } + + function _collectCertHints(bytes memory cert, bytes memory parentPubKey) internal returns (bytes memory) { + string[] memory command = new string[](7); + command[0] = "node"; + command[1] = "lib/nitro-validator/tools/p384_hints.js"; + command[2] = "cert"; + command[3] = "--cert"; + command[4] = vm.toString(cert); + command[5] = "--pubkey"; + command[6] = vm.toString(parentPubKey); + return vm.ffi(command); + } + + function _collectVerifyHints( + bytes memory hash, + bytes memory signature, + bytes memory pubKey + ) + internal + returns (bytes memory) + { + string[] memory command = new string[](9); + command[0] = "node"; + command[1] = "lib/nitro-validator/tools/p384_hints.js"; + command[2] = "verify"; + command[3] = "--hash"; + command[4] = vm.toString(hash); + command[5] = "--signature"; + command[6] = vm.toString(signature); + command[7] = "--pubkey"; + command[8] = vm.toString(pubKey); + return vm.ffi(command); + } + + function _loadRealAttestation() internal returns (bytes memory) { + string[] memory command = new string[](3); + command[0] = "node"; + command[1] = "-e"; + command[2] = string.concat( + "process.chdir('lib/nitro-validator');", + "const t=require(process.cwd()+'/tools/nitro_attestation_input.js');", + "const a=t.repairMissingPublicKeyBytes(t.realFixture());", + "process.stdout.write('0x'+a.toString('hex'));" + ); + return vm.ffi(command); + } + + function _deployValidatorStack() + internal + returns (IP384Verifier p384Verifier_, ICertManager certManager_, NitroValidator nitroValidator_) + { + address deployScript = _deployCode("DeployNitroValidatorStack", ""); + (bool success, bytes memory returndata) = + deployScript.call(abi.encodeWithSignature("run(address,address)", address(this), address(this))); + require(success, "stack deployment failed"); + (address p384VerifierAddr, address certManagerAddr, address nitroValidatorAddr) = + abi.decode(returndata, (address, address, address)); + p384Verifier_ = IP384Verifier(p384VerifierAddr); + certManager_ = ICertManager(certManagerAddr); + nitroValidator_ = NitroValidator(nitroValidatorAddr); + } + + function _deployRegistry(NitroValidator nitroValidator_) internal returns (TEEProverRegistry registry_) { + MockAggregateVerifierForRegistry verifier = new MockAggregateVerifierForRegistry(bytes32(uint256(1))); + MockDisputeGameFactoryForRegistry factory = new MockDisputeGameFactoryForRegistry(address(verifier)); + TEEProverRegistry impl = new TEEProverRegistry({ + nitroValidator: INitroValidator(address(nitroValidator_)), factory: IDisputeGameFactory(address(factory)) + }); + + address proxyAdmin = makeAddr("real-attestation-proxy-admin"); + Proxy proxy = new Proxy(proxyAdmin); + vm.prank(proxyAdmin); + proxy.upgradeToAndCall( + address(impl), + abi.encodeCall( + TEEProverRegistry.initialize, (address(this), address(this), new address[](0), TEST_GAME_TYPE) + ) + ); + registry_ = TEEProverRegistry(address(proxy)); + } + + function _deployCode(string memory artifact, bytes memory args) internal returns (address deployed_) { + string[] memory command = new string[](4); + command[0] = "forge"; + command[1] = "inspect"; + command[2] = artifact; + command[3] = "bytecode"; + bytes memory creationCode = abi.encodePacked(vm.ffi(command), args); + assembly { + deployed_ := create(0, add(creationCode, 0x20), mload(creationCode)) + } + require(deployed_ != address(0), "deployment failed"); + } + + function _calldataGas(bytes memory data) internal pure returns (uint256 gas_) { + for (uint256 i = 0; i < data.length; i++) { + gas_ += data[i] == bytes1(0) ? 4 : 16; + } + } } diff --git a/test/L1/proofs/TEEVerifier.t.sol b/test/L1/proofs/TEEVerifier.t.sol index 5059cb840..c957ba87f 100644 --- a/test/L1/proofs/TEEVerifier.t.sol +++ b/test/L1/proofs/TEEVerifier.t.sol @@ -5,9 +5,9 @@ import { Test } from "lib/forge-std/src/Test.sol"; import { Proxy } from "src/universal/Proxy.sol"; -import { INitroEnclaveVerifier } from "interfaces/L1/proofs/tee/INitroEnclaveVerifier.sol"; import { IAnchorStateRegistry } from "interfaces/L1/proofs/IAnchorStateRegistry.sol"; import { IDisputeGameFactory } from "interfaces/L1/proofs/IDisputeGameFactory.sol"; +import { INitroValidator } from "interfaces/L1/proofs/tee/INitroValidator.sol"; import { GameType } from "src/libraries/bridge/Types.sol"; import { IDisputeGame } from "interfaces/L1/proofs/IDisputeGame.sol"; @@ -52,8 +52,9 @@ contract TEEVerifierTest is Test { MockDisputeGameFactoryForVerifier mockFactory = new MockDisputeGameFactoryForVerifier(address(mockVerifier)); // DevTEEProverRegistry keeps these tests focused on verifier behavior without Nitro attestation setup. - DevTEEProverRegistry impl = - new DevTEEProverRegistry(INitroEnclaveVerifier(address(0)), IDisputeGameFactory(address(mockFactory))); + DevTEEProverRegistry impl = new DevTEEProverRegistry({ + nitroValidator: INitroValidator(address(0)), factory: IDisputeGameFactory(address(mockFactory)) + }); address proxyAdmin = makeAddr("proxy-admin"); Proxy proxy = new Proxy(proxyAdmin); diff --git a/test/deploy/SystemDeploy.t.sol b/test/deploy/SystemDeploy.t.sol index 93428e058..9c44b0dd2 100644 --- a/test/deploy/SystemDeploy.t.sol +++ b/test/deploy/SystemDeploy.t.sol @@ -9,6 +9,8 @@ import { Types } from "scripts/libraries/Types.sol"; import { SystemDeployAssertions } from "test/deploy/SystemDeployAssertions.sol"; import { ISP1Verifier } from "interfaces/L1/proofs/zk/ISP1Verifier.sol"; +import { IDisputeGameFactory } from "interfaces/L1/proofs/IDisputeGameFactory.sol"; +import { INitroValidator } from "interfaces/L1/proofs/tee/INitroValidator.sol"; import { IProtocolVersions } from "interfaces/L1/IProtocolVersions.sol"; import { ProtocolVersions } from "src/L1/ProtocolVersions.sol"; import { AggregateVerifier } from "src/L1/proofs/AggregateVerifier.sol"; @@ -17,6 +19,8 @@ import { TEEVerifier } from "src/L1/proofs/tee/TEEVerifier.sol"; import { ZKVerifier } from "src/L1/proofs/zk/ZKVerifier.sol"; import { GameType, Hash, Proposal } from "src/libraries/bridge/Types.sol"; import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; +import { DevTEEProverRegistry } from "test/mocks/MockDevTEEProverRegistry.sol"; +import { MockNitroValidator } from "test/mocks/MockNitroValidator.sol"; contract MockNitroEnclaveVerifier { address public proofSubmitter; @@ -26,6 +30,19 @@ contract MockNitroEnclaveVerifier { } } +contract MockLegacyTEEProverRegistry is DevTEEProverRegistry { + constructor( + INitroValidator nitroValidator, + IDisputeGameFactory factory + ) + DevTEEProverRegistry(nitroValidator, factory) + { } + + function version() public pure override returns (string memory) { + return "0.5.0"; + } +} + contract MockSP1Verifier { function verifyProof(bytes32, bytes calldata, bytes calldata) external pure { } } @@ -43,6 +60,7 @@ contract SystemDeploy_Test is Test, SystemDeployAssertions { address internal proposer = makeAddr("proposer"); address internal challenger = makeAddr("challenger"); MockNitroEnclaveVerifier internal nitroEnclaveVerifier; + MockNitroValidator internal nitroValidator; MockSP1Verifier internal sp1Verifier; uint256 internal l2ChainId = 901; @@ -50,6 +68,7 @@ contract SystemDeploy_Test is Test, SystemDeployAssertions { function setUp() public { systemDeploy = new SystemDeploy(); nitroEnclaveVerifier = new MockNitroEnclaveVerifier(); + nitroValidator = new MockNitroValidator(); sp1Verifier = new MockSP1Verifier(); } @@ -162,6 +181,35 @@ contract SystemDeploy_Test is Test, SystemDeployAssertions { systemDeploy.deploy(input); } + function test_deploy_withoutNitroValidator_reverts() public { + SystemDeploy.DeployInput memory input = _defaultDeployInput(); + input.implementationsInput.nitroValidator = address(0); + + vm.expectRevert("SystemDeploy: nitroValidator not set"); + systemDeploy.deploy(input); + } + + function test_upgrade_registryWithInvalidNitroValidator_reverts() public { + SystemDeploy.DeployInput memory input = _defaultDeployInput(); + SystemDeploy.DeployOutput memory output = systemDeploy.deploy(input); + TEEProverRegistry invalidRegistryImpl = new TEEProverRegistry({ + nitroValidator: INitroValidator(address(0)), factory: output.opChain.disputeGameFactoryProxy + }); + Types.Implementations memory implementations = output.impls; + implementations.teeProverRegistryImpl = address(invalidRegistryImpl); + + vm.expectRevert("DeployUtils: zero address"); + systemDeploy.upgrade( + SystemDeploy.UpgradeInput({ + saveArtifacts: false, + superchainConfigProxy: output.superchain.superchainConfigProxy, + implementations: implementations, + systemConfigProxy: output.opChain.systemConfigProxy, + protocolVersionsProxy: output.opChain.protocolVersionsProxy + }) + ); + } + function test_upgrade_withoutManagerDelegatecall_succeeds() public { SystemDeploy.DeployInput memory input = _defaultDeployInput(); SystemDeploy.DeployOutput memory output = systemDeploy.deploy(input); @@ -195,6 +243,50 @@ contract SystemDeploy_Test is Test, SystemDeployAssertions { assertValidStandardSystem(_expected(output, input)); } + function test_upgrade_predeployedTEEProverRegistryImplementation_succeeds() public { + SystemDeploy.DeployInput memory input = _defaultDeployInput(); + SystemDeploy.DeployOutput memory output = systemDeploy.deploy(input); + TEEProverRegistry registry = TEEProverRegistry(address(output.opChain.teeProverRegistryProxy)); + MockLegacyTEEProverRegistry legacyImpl = new MockLegacyTEEProverRegistry({ + nitroValidator: INitroValidator(address(nitroValidator)), factory: registry.DISPUTE_GAME_FACTORY() + }); + output.opChain.opChainProxyAdmin.upgrade(payable(address(registry)), address(legacyImpl)); + + address signer = makeAddr("existing-signer"); + bytes32 imageHash = keccak256("existing-image"); + DevTEEProverRegistry(address(registry)).addDevSigner(signer, imageHash); + + TEEProverRegistry newImpl = new TEEProverRegistry({ + nitroValidator: INitroValidator(address(nitroValidator)), factory: registry.DISPUTE_GAME_FACTORY() + }); + Types.Implementations memory implementations = output.impls; + implementations.teeProverRegistryImpl = address(newImpl); + systemDeploy.upgrade( + SystemDeploy.UpgradeInput({ + saveArtifacts: false, + superchainConfigProxy: output.superchain.superchainConfigProxy, + implementations: implementations, + systemConfigProxy: output.opChain.systemConfigProxy, + protocolVersionsProxy: output.opChain.protocolVersionsProxy + }) + ); + + assertEq( + output.opChain.opChainProxyAdmin.getProxyImplementation(address(registry)), + address(newImpl), + "tee registry impl" + ); + assertEq(registry.version(), "0.6.0"); + assertEq(registry.owner(), owner); + assertEq(registry.manager(), owner); + assertEq(GameType.unwrap(registry.gameType()), uint32(input.implementationsInput.multiproofGameType)); + assertTrue(registry.isValidProposer(proposer)); + assertTrue(registry.isValidProposer(challenger)); + assertTrue(registry.isRegisteredSigner(signer)); + assertEq(registry.signerImageHash(signer), imageHash); + assertEq(address(registry.NITRO_VALIDATOR()), address(nitroValidator)); + } + function test_upgrade_discoversProtocolVersionsProxyFromArtifacts_succeeds() public { SystemDeploy.DeployInput memory input = _defaultDeployInput(); SystemDeploy.DeployOutput memory output = systemDeploy.deploy(input); @@ -258,6 +350,7 @@ contract SystemDeploy_Test is Test, SystemDeployAssertions { multiproofConfigHash: bytes32(uint256(4)), multiproofGameType: 621, nitroEnclaveVerifier: address(nitroEnclaveVerifier), + nitroValidator: address(nitroValidator), scheduleConfig: AggregateVerifier.ScheduleConfig({ protocolVersions: IProtocolVersions(address(0)), genesisBlockNumber: 0, @@ -311,6 +404,7 @@ contract SystemDeploy_Test is Test, SystemDeployAssertions { _input.implementationsInput.nitroEnclaveVerifier, "nitro enclave verifier" ); + assertEq(address(_output.opChain.nitroValidator), _input.implementationsInput.nitroValidator, "nitro validator"); assertEq(address(_output.opChain.sp1Verifier), address(_input.implementationsInput.sp1Verifier), "sp1 verifier"); assertEq( _output.opChain.opChainProxyAdmin.getProxyImplementation(teeProverRegistryProxyAddr), @@ -325,13 +419,13 @@ contract SystemDeploy_Test is Test, SystemDeployAssertions { assertTrue(teeProverRegistry.isValidProposer(_input.implementationsInput.teeChallenger), "tee challenger"); assertEq( MockNitroEnclaveVerifier(_input.implementationsInput.nitroEnclaveVerifier).proofSubmitter(), - teeProverRegistryProxyAddr, - "nitro proof submitter" + address(0), + "legacy nitro proof submitter" ); assertEq( - address(teeProverRegistry.NITRO_VERIFIER()), - _input.implementationsInput.nitroEnclaveVerifier, - "tee registry nitro verifier" + address(teeProverRegistry.NITRO_VALIDATOR()), + _input.implementationsInput.nitroValidator, + "tee registry nitro validator" ); assertEq( address(teeProverRegistry.DISPUTE_GAME_FACTORY()), diff --git a/test/mocks/MockDevTEEProverRegistry.sol b/test/mocks/MockDevTEEProverRegistry.sol index eea6d9a2b..31fef0382 100644 --- a/test/mocks/MockDevTEEProverRegistry.sol +++ b/test/mocks/MockDevTEEProverRegistry.sol @@ -1,11 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.15; -import { INitroEnclaveVerifier } from "interfaces/L1/proofs/tee/INitroEnclaveVerifier.sol"; +import { EnumerableSetLib } from "src/vendor/EnumerableSetLib.sol"; import { IDisputeGameFactory } from "interfaces/L1/proofs/IDisputeGameFactory.sol"; - +import { INitroValidator } from "interfaces/L1/proofs/tee/INitroValidator.sol"; import { TEEProverRegistry } from "src/L1/proofs/tee/TEEProverRegistry.sol"; -import { EnumerableSetLib } from "src/vendor/EnumerableSetLib.sol"; /// @title DevTEEProverRegistry /// @notice Test/development registry that can register signers without Nitro attestation verification. @@ -14,10 +13,10 @@ contract DevTEEProverRegistry is TEEProverRegistry { using EnumerableSetLib for EnumerableSetLib.AddressSet; constructor( - INitroEnclaveVerifier nitroVerifier, + INitroValidator nitroValidator, IDisputeGameFactory factory ) - TEEProverRegistry(nitroVerifier, factory) + TEEProverRegistry(nitroValidator, factory) { } /// @notice Registers a signer and image hash without attestation verification. diff --git a/test/mocks/MockNitroValidator.sol b/test/mocks/MockNitroValidator.sol new file mode 100644 index 000000000..8736dfa8d --- /dev/null +++ b/test/mocks/MockNitroValidator.sol @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +contract MockNitroValidator { } diff --git a/test/setup/Setup.sol b/test/setup/Setup.sol index 7ee901cb4..230ad88f7 100644 --- a/test/setup/Setup.sol +++ b/test/setup/Setup.sol @@ -35,6 +35,8 @@ import { IOptimismMintableERC721Factory } from "interfaces/L2/IOptimismMintableE import { IDisputeGameFactory } from "interfaces/L1/proofs/IDisputeGameFactory.sol"; import { IDelayedWETH } from "interfaces/L1/proofs/IDelayedWETH.sol"; import { IAnchorStateRegistry } from "interfaces/L1/proofs/IAnchorStateRegistry.sol"; +import { INitroEnclaveVerifier } from "interfaces/L1/proofs/tee/INitroEnclaveVerifier.sol"; +import { INitroValidator } from "interfaces/L1/proofs/tee/INitroValidator.sol"; import { IL2CrossDomainMessenger } from "interfaces/L2/IL2CrossDomainMessenger.sol"; import { IL2StandardBridge } from "interfaces/L2/IL2StandardBridge.sol"; import { IL2ToL1MessagePasser } from "interfaces/L2/IL2ToL1MessagePasser.sol"; @@ -123,6 +125,8 @@ abstract contract Setup is FeatureFlags { IGasPriceOracle gasPriceOracle = IGasPriceOracle(Predeploys.GAS_PRICE_ORACLE); IL1Block l1Block = IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES); IWETH98 weth = IWETH98(payable(Predeploys.WETH)); + INitroEnclaveVerifier nitroEnclaveVerifier; + INitroValidator nitroValidator; TEEProverRegistry teeProverRegistry; /// @notice Indicates whether a test is running against a forked production network. @@ -239,6 +243,8 @@ abstract contract Setup is FeatureFlags { proxyAdminOwner = proxyAdmin.owner(); superchainProxyAdmin = IProxyAdmin(EIP1967Helper.getAdmin(address(superchainConfig))); superchainProxyAdminOwner = superchainProxyAdmin.owner(); + nitroEnclaveVerifier = INitroEnclaveVerifier(artifacts.getAddress("NitroEnclaveVerifier")); + nitroValidator = INitroValidator(artifacts.getAddress("NitroValidator")); teeProverRegistry = TEEProverRegistry(artifacts.getAddress("TEEProverRegistry")); console.log("Setup: registered L1 deployments");