From 38594f37b5f6d1b1f5f6ad4203a4770c10f72a22 Mon Sep 17 00:00:00 2001 From: Mateusz Morusiewicz <11313015+Ruteri@users.noreply.github.com> Date: Tue, 18 Nov 2025 15:39:25 -0400 Subject: [PATCH] remove xfam + tdAttributes bitmasking logic, and add upgrade script + documentation for v1 block builder policy migration This PR introduces the V1BlockBuilderPolicy contract and corresponding upgrade script to migrate from the initial policy version that contained buggy xFAM and td attributes bit masking logic. The upgrade provides a cleaner implementation without bit masking, following the bug fix completed in the previous commit. Documentation is added to the README explaining the upgrade rationale and deployment commands. --- README.md | 20 ++ script/UpgradeBlockBuilderFromV1.s.sol | 54 +++++ src/BlockBuilderPolicy.sol | 26 +-- src/V1BlockBuilderPolicy.sol | 302 +++++++++++++++++++++++++ test/BlockBuilderPolicy.t.sol | 81 ------- 5 files changed, 378 insertions(+), 105 deletions(-) create mode 100644 script/UpgradeBlockBuilderFromV1.s.sol create mode 100644 src/V1BlockBuilderPolicy.sol diff --git a/README.md b/README.md index 84fedcb..cd87368 100644 --- a/README.md +++ b/README.md @@ -259,3 +259,23 @@ Then, to execute, run: ``` forge script --chain 1301 script/Interactions.s.sol:AddWorkloadToPolicyScript --rpc-url $RPC_URL --broadcast --verify --interactives 1 -vvvv ``` + +## Upgrade + +### UpgradeBlockBuilderFromV1 + +#### Reason For Upgrade + +This is nearly identical to the latest version of the policy contract located at src/BlockBuilderPolicy contract, except in the latest has had the logic around the xfam and tdattributes bit masking removed. This was done because there was a bug in the bit masking logic, and we want to fix the bug and simplify the contract by removing the bit masking logic. + +#### Deploy Command + +Run the command below, then paste in the private key of the address you want to use to pay for gas and execute the deployment: + +``` +forge script script/UpgradeBlockBuilderFromV1.s.sol:UpgradeBlockBuilderPolicyV1 \ + --sig "run(address)" \ + --rpc-url \ + -vvvvv --verify --broadcast --interactives 1 +``` + diff --git a/script/UpgradeBlockBuilderFromV1.s.sol b/script/UpgradeBlockBuilderFromV1.s.sol new file mode 100644 index 0000000..cc2bb6b --- /dev/null +++ b/script/UpgradeBlockBuilderFromV1.s.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Script, console} from "forge-std/Script.sol"; +import {Upgrades, Options} from "openzeppelin-foundry-upgrades/Upgrades.sol"; +import {BlockBuilderPolicy} from "../src/BlockBuilderPolicy.sol"; + +/** + * @title UpgradeBlockBuilderFromV1 + * @notice Upgrade script for BlockBuilderPolicy contract from V1 (the original version of the contract) + * @notice This is nearly identical to the latest version of the policy contract located at + * src/BlockBuilderPolicy contract, except in the latest has had the logic around the xfam and tdattributes bit + * masking removed. This was done because there was a bug in the bit masking logic, and we want to fix the bug + * and simplify the contract by removing the bit masking logic + * @dev This script does not require any reinitialization of the contract, as the the only changes to + * the contract are removing constant variables and changing the workloadIdForTDRegistration function logic + * @dev This script: + * 1. Deploys a new BlockBuilderPolicy implementation contract + * 2. Upgrades the existing UUPS proxy to point to the new implementation + */ +contract UpgradeBlockBuilderPolicyV1 is Script { + /** + * @notice uses environment variables to get the proxy address of the BlockBuilderPolicy contract + * @dev the BLOCK_BUILDER_POLICY_PROXY_ADDRESS env var is the address of the proxy contract for the BlockBuilderPolicy contract + */ + function run() external { + address proxyAddress = vm.envAddress("BLOCK_BUILDER_POLICY_PROXY_ADDRESS"); + run(proxyAddress); + } + + function run(address proxyAddress) public { + console.log("=== UpgradeBlockBuilderFromV1 Configuration ==="); + console.log("Proxy address:", proxyAddress); + console.log(""); + + // Spot check the proxy contract by calling the registry function + // This is a safety check to ensure the contract at the proxy address + // implements IBlockBuilderPolicy as expected + address proxyRegistry = BlockBuilderPolicy(proxyAddress).registry(); + require(proxyRegistry != address(0), "proxyAddress is not a BlockBuilderPolicy contract"); + + vm.startBroadcast(); + + // Upgrade the proxy to the new implementation + Options memory opts; + opts.referenceContract = "V1BlockBuilderPolicy.sol:V1BlockBuilderPolicy"; + Upgrades.upgradeProxy(proxyAddress, "BlockBuilderPolicy.sol", bytes(""), opts); + + vm.stopBroadcast(); + + console.log("=== Upgrade Complete ==="); + console.log(""); + } +} diff --git a/src/BlockBuilderPolicy.sol b/src/BlockBuilderPolicy.sol index fcb7590..3873485 100644 --- a/src/BlockBuilderPolicy.sol +++ b/src/BlockBuilderPolicy.sol @@ -47,22 +47,6 @@ contract BlockBuilderPolicy is bytes32 public constant VERIFY_BLOCK_BUILDER_PROOF_TYPEHASH = keccak256("VerifyBlockBuilderProof(uint8 version,bytes32 blockContentHash,uint256 nonce)"); - // ============ TDX workload constants ============ - - /// @dev See section 11.5.3 in TDX Module v1.5 Base Architecture Specification https://www.intel.com/content/www/us/en/content-details/733575/intel-tdx-module-v1-5-base-architecture-specification.html - /// @notice Enabled FPU (always enabled) - bytes8 constant TD_XFAM_FPU = 0x0000000000000001; - /// @notice Enabled SSE (always enabled) - bytes8 constant TD_XFAM_SSE = 0x0000000000000002; - - /// @dev See section 3.4.1 in TDX Module ABI specification https://cdrdv2.intel.com/v1/dl/getContent/733579 - /// @notice Allows disabling of EPT violation conversion to #VE on access of PENDING pages. Needed for Linux - bytes8 constant TD_TDATTRS_VE_DISABLED = 0x0000000010000000; - /// @notice Enabled Supervisor Protection Keys (PKS) - bytes8 constant TD_TDATTRS_PKS = 0x0000000040000000; - /// @notice Enabled Key Locker (KL) - bytes8 constant TD_TDATTRS_KL = 0x0000000080000000; - // ============ Storage Variables ============ /// @notice Mapping from workloadId to its metadata (commit hash and source locators) @@ -227,12 +211,6 @@ contract BlockBuilderPolicy is override returns (WorkloadId) { - // We expect FPU and SSE xfam bits to be set, and anything else should be handled by explicitly allowing the workloadid - bytes8 expectedXfamBits = TD_XFAM_FPU | TD_XFAM_SSE; - - // We don't mind VE_DISABLED, PKS, and KL tdattributes bits being set either way, anything else requires explicitly allowing the workloadid - bytes8 ignoredTdAttributesBitmask = TD_TDATTRS_VE_DISABLED | TD_TDATTRS_PKS | TD_TDATTRS_KL; - return WorkloadId.wrap( keccak256( bytes.concat( @@ -243,8 +221,8 @@ contract BlockBuilderPolicy is registration.parsedReportBody.rtMr3, // VMM configuration registration.parsedReportBody.mrConfigId, - registration.parsedReportBody.xFAM ^ expectedXfamBits, - registration.parsedReportBody.tdAttributes & ~ignoredTdAttributesBitmask + registration.parsedReportBody.xFAM, + registration.parsedReportBody.tdAttributes ) ) ); diff --git a/src/V1BlockBuilderPolicy.sol b/src/V1BlockBuilderPolicy.sol new file mode 100644 index 0000000..d8eeff9 --- /dev/null +++ b/src/V1BlockBuilderPolicy.sol @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {EIP712Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol"; +import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; +import {FlashtestationRegistry} from "./FlashtestationRegistry.sol"; +import {IFlashtestationRegistry} from "./interfaces/IFlashtestationRegistry.sol"; +import {IBlockBuilderPolicy, WorkloadId} from "./interfaces/IBlockBuilderPolicy.sol"; + +/** + * @notice Cached workload information for gas optimization + * @dev Stores computed workloadId and associated quoteHash to avoid expensive recomputation + */ +struct CachedWorkload { + /// @notice The computed workload identifier + WorkloadId workloadId; + /// @notice The keccak256 hash of the raw quote used to compute this workloadId + bytes32 quoteHash; +} + +/** + * @title V1BlockBuilderPolicy + * @notice This is nearly identical to the latest version of the policy contract located at + * src/BlockBuilderPolicy contract, except in the latest has had the logic around the xfam and tdattributes bit + * masking removed. This was done because there was a bug in the bit masking logic, and we want to fix the bug + * and simplify the contract by removing the bit masking logic + * + */ +contract V1BlockBuilderPolicy is + Initializable, + UUPSUpgradeable, + OwnableUpgradeable, + EIP712Upgradeable, + IBlockBuilderPolicy +{ + using ECDSA for bytes32; + + // ============ EIP-712 Constants ============ + + /// @inheritdoc IBlockBuilderPolicy + bytes32 public constant VERIFY_BLOCK_BUILDER_PROOF_TYPEHASH = + keccak256("VerifyBlockBuilderProof(uint8 version,bytes32 blockContentHash,uint256 nonce)"); + + // ============ TDX workload constants ============ + + /// @dev See section 11.5.3 in TDX Module v1.5 Base Architecture Specification https://www.intel.com/content/www/us/en/content-details/733575/intel-tdx-module-v1-5-base-architecture-specification.html + /// @notice Enabled FPU (always enabled) + bytes8 constant TD_XFAM_FPU = 0x0000000000000001; + /// @notice Enabled SSE (always enabled) + bytes8 constant TD_XFAM_SSE = 0x0000000000000002; + + /// @dev See section 3.4.1 in TDX Module ABI specification https://cdrdv2.intel.com/v1/dl/getContent/733579 + /// @notice Allows disabling of EPT violation conversion to #VE on access of PENDING pages. Needed for Linux + bytes8 constant TD_TDATTRS_VE_DISABLED = 0x0000000010000000; + /// @notice Enabled Supervisor Protection Keys (PKS) + bytes8 constant TD_TDATTRS_PKS = 0x0000000040000000; + /// @notice Enabled Key Locker (KL) + bytes8 constant TD_TDATTRS_KL = 0x0000000080000000; + + // ============ Storage Variables ============ + + /// @notice Mapping from workloadId to its metadata (commit hash and source locators) + /// @dev This is only updateable by governance (i.e. the owner) of the Policy contract + /// Adding and removing a workload is O(1). + /// This means the critical `_cachedIsAllowedPolicy` function is O(1) since we can directly check if a workloadId exists + /// in the mapping + mapping(bytes32 workloadId => WorkloadMetadata) private approvedWorkloads; + + /// @inheritdoc IBlockBuilderPolicy + address public registry; + + /// @inheritdoc IBlockBuilderPolicy + mapping(address teeAddress => uint256 permitNonce) public nonces; + + /// @notice Cache of computed workloadIds to avoid expensive recomputation + /// @dev Maps teeAddress to cached workload information for gas optimization + mapping(address teeAddress => CachedWorkload) private cachedWorkloads; + + /// @dev Storage gap to allow for future storage variable additions in upgrades + /// @dev This reserves 46 storage slots (out of 50 total - 4 used for approvedWorkloads, registry, nonces, and cachedWorkloads) + uint256[46] __gap; + + /// @inheritdoc IBlockBuilderPolicy + function initialize(address _initialOwner, address _registry) external override initializer { + __Ownable_init(_initialOwner); + __UUPSUpgradeable_init(); + __EIP712_init("BlockBuilderPolicy", "1"); + require(_registry != address(0), InvalidRegistry()); + + registry = _registry; + emit RegistrySet(_registry); + } + + /// @notice Restricts upgrades to owner only + /// @param newImplementation The address of the new implementation contract + function _authorizeUpgrade(address newImplementation) internal override onlyOwner {} + + /// @inheritdoc IBlockBuilderPolicy + function verifyBlockBuilderProof(uint8 version, bytes32 blockContentHash) external override { + _verifyBlockBuilderProof(msg.sender, version, blockContentHash); + } + + /// @inheritdoc IBlockBuilderPolicy + function permitVerifyBlockBuilderProof( + uint8 version, + bytes32 blockContentHash, + uint256 nonce, + bytes calldata eip712Sig + ) external override { + // Get the TEE address from the signature + bytes32 digest = getHashedTypeDataV4(computeStructHash(version, blockContentHash, nonce)); + address teeAddress = digest.recover(eip712Sig); + + // Verify the nonce + uint256 expectedNonce = nonces[teeAddress]; + require(nonce == expectedNonce, InvalidNonce(expectedNonce, nonce)); + + // Increment the nonce + nonces[teeAddress]++; + + // Verify the block builder proof + _verifyBlockBuilderProof(teeAddress, version, blockContentHash); + } + + /// @notice Internal function to verify a block builder proof + /// @dev This function is internal because it is only used by the permitVerifyBlockBuilderProof function + /// and it is not needed to be called by other contracts + /// @param teeAddress The TEE-controlled address + /// @param version The version of the flashtestation's protocol + /// @param blockContentHash The hash of the block content + function _verifyBlockBuilderProof(address teeAddress, uint8 version, bytes32 blockContentHash) internal { + // Check if the caller is an authorized TEE block builder for our Policy and update cache + (bool allowed, WorkloadId workloadId) = _cachedIsAllowedPolicy(teeAddress); + require(allowed, UnauthorizedBlockBuilder(teeAddress)); + + // At this point, we know: + // 1. The caller is a registered TEE-controlled address from an attested TEE + // 2. The TEE is running an approved block builder workload (via policy) + + // Note: Due to EVM limitations (no retrospection), we cannot validate the blockContentHash + // onchain. We rely on the TEE workload to correctly compute this hash according to the + // specified version of the calculation method. + + bytes32 workloadKey = WorkloadId.unwrap(workloadId); + string memory commitHash = approvedWorkloads[workloadKey].commitHash; + emit BlockBuilderProofVerified(teeAddress, workloadKey, version, blockContentHash, commitHash); + } + + /// @inheritdoc IBlockBuilderPolicy + function isAllowedPolicy(address teeAddress) public view override returns (bool allowed, WorkloadId) { + // Get full registration data and compute workload ID + (, IFlashtestationRegistry.RegisteredTEE memory registration) = + FlashtestationRegistry(registry).getRegistration(teeAddress); + + // Invalid Registrations means the attestation used to register the TEE is no longer valid + // and so we cannot trust any input from the TEE + if (!registration.isValid) { + return (false, WorkloadId.wrap(0)); + } + + WorkloadId workloadId = workloadIdForTDRegistration(registration); + + // Check if the workload exists in our approved workloads mapping + if (bytes(approvedWorkloads[WorkloadId.unwrap(workloadId)].commitHash).length > 0) { + return (true, workloadId); + } + + return (false, WorkloadId.wrap(0)); + } + + /// @notice isAllowedPolicy but with caching to reduce gas costs + /// @dev This function is only used by the verifyBlockBuilderProof function, which needs to be as efficient as possible + /// because it is called onchain for every flashblock. The workloadId is cached to avoid expensive recomputation + /// @dev A careful reader will notice that this function does not delete stale cache entries. It overwrites them + /// if the underlying TEE registration is still valid. But for stale cache entries in every other scenario, the + /// cache entry persists indefinitely. This is because every other instance results in a return value of (false, 0) + /// to the caller (which is always the verifyBlockBuilderProof function) and it immediately reverts. This is an unfortunate + /// consequence of our need to make this function as gas-efficient as possible, otherwise we would try to cleanup + /// stale cache entries + /// @param teeAddress The TEE-controlled address + /// @return True if the TEE is using an approved workload in the policy + /// @return The workloadId of the TEE that is using an approved workload in the policy, or 0 if + /// the TEE is not using an approved workload in the policy + function _cachedIsAllowedPolicy(address teeAddress) private returns (bool, WorkloadId) { + // Get the current registration status (fast path) + (bool isValid, bytes32 quoteHash) = FlashtestationRegistry(registry).getRegistrationStatus(teeAddress); + if (!isValid) { + return (false, WorkloadId.wrap(0)); + } + + // Now, check if we have a cached workload for this TEE + CachedWorkload memory cached = cachedWorkloads[teeAddress]; + + // Check if we've already fetched and computed the workloadId for this TEE + bytes32 cachedWorkloadId = WorkloadId.unwrap(cached.workloadId); + if (cachedWorkloadId != 0 && cached.quoteHash == quoteHash) { + // Cache hit - verify the workload is still a part of this policy's approved workloads + if (bytes(approvedWorkloads[cachedWorkloadId].commitHash).length > 0) { + return (true, cached.workloadId); + } else { + // The workload is no longer approved, so the policy is no longer valid for this TEE\ + return (false, WorkloadId.wrap(0)); + } + } else { + // Cache miss or quote changed - use the view function to get the result + (bool allowed, WorkloadId workloadId) = isAllowedPolicy(teeAddress); + + if (allowed) { + // Update cache with the new workload ID + cachedWorkloads[teeAddress] = CachedWorkload({workloadId: workloadId, quoteHash: quoteHash}); + } + + return (allowed, workloadId); + } + } + + /// @inheritdoc IBlockBuilderPolicy + function workloadIdForTDRegistration(IFlashtestationRegistry.RegisteredTEE memory registration) + public + pure + override + returns (WorkloadId) + { + // We expect FPU and SSE xfam bits to be set, and anything else should be handled by explicitly allowing the workloadid + bytes8 expectedXfamBits = TD_XFAM_FPU | TD_XFAM_SSE; + + // We don't mind VE_DISABLED, PKS, and KL tdattributes bits being set either way, anything else requires explicitly allowing the workloadid + bytes8 ignoredTdAttributesBitmask = TD_TDATTRS_VE_DISABLED | TD_TDATTRS_PKS | TD_TDATTRS_KL; + + return WorkloadId.wrap( + keccak256( + bytes.concat( + registration.parsedReportBody.mrTd, + registration.parsedReportBody.rtMr0, + registration.parsedReportBody.rtMr1, + registration.parsedReportBody.rtMr2, + registration.parsedReportBody.rtMr3, + // VMM configuration + registration.parsedReportBody.mrConfigId, + registration.parsedReportBody.xFAM ^ expectedXfamBits, + registration.parsedReportBody.tdAttributes & ~ignoredTdAttributesBitmask + ) + ) + ); + } + + /// @inheritdoc IBlockBuilderPolicy + function addWorkloadToPolicy(WorkloadId workloadId, string calldata commitHash, string[] calldata sourceLocators) + external + override + onlyOwner + { + require(bytes(commitHash).length > 0, EmptyCommitHash()); + require(sourceLocators.length > 0, EmptySourceLocators()); + + bytes32 workloadKey = WorkloadId.unwrap(workloadId); + + // Check if workload already exists + require(bytes(approvedWorkloads[workloadKey].commitHash).length == 0, WorkloadAlreadyInPolicy()); + + // Store the workload metadata + approvedWorkloads[workloadKey] = WorkloadMetadata({commitHash: commitHash, sourceLocators: sourceLocators}); + + emit WorkloadAddedToPolicy(workloadKey); + } + + /// @inheritdoc IBlockBuilderPolicy + function removeWorkloadFromPolicy(WorkloadId workloadId) external override onlyOwner { + bytes32 workloadKey = WorkloadId.unwrap(workloadId); + + // Check if workload exists + require(bytes(approvedWorkloads[workloadKey].commitHash).length > 0, WorkloadNotInPolicy()); + + // Remove the workload metadata + delete approvedWorkloads[workloadKey]; + + emit WorkloadRemovedFromPolicy(workloadKey); + } + + /// @inheritdoc IBlockBuilderPolicy + function getWorkloadMetadata(WorkloadId workloadId) external view override returns (WorkloadMetadata memory) { + return approvedWorkloads[WorkloadId.unwrap(workloadId)]; + } + + /// @inheritdoc IBlockBuilderPolicy + function getHashedTypeDataV4(bytes32 structHash) public view returns (bytes32) { + return _hashTypedDataV4(structHash); + } + + /// @inheritdoc IBlockBuilderPolicy + function computeStructHash(uint8 version, bytes32 blockContentHash, uint256 nonce) public pure returns (bytes32) { + return keccak256(abi.encode(VERIFY_BLOCK_BUILDER_PROOF_TYPEHASH, version, blockContentHash, nonce)); + } + + /// @inheritdoc IBlockBuilderPolicy + function domainSeparator() external view returns (bytes32) { + return _domainSeparatorV4(); + } +} diff --git a/test/BlockBuilderPolicy.t.sol b/test/BlockBuilderPolicy.t.sol index 4e274d9..03ec96e 100644 --- a/test/BlockBuilderPolicy.t.sol +++ b/test/BlockBuilderPolicy.t.sol @@ -359,87 +359,6 @@ contract BlockBuilderPolicyTest is Test { assertEq(WorkloadId.unwrap(computedWorkloadIdF200), WorkloadId.unwrap(computedWorkloadId12c1)); } - // Add these test functions to BlockBuilderPolicyTest contract - - function test_workloadId_tdAttributes_allowed_bits_ignored() public { - // Register a TEE to get a baseline - _registerTEE(mockf200); - (, IFlashtestationRegistry.RegisteredTEE memory baseRegistration) = - registry.getRegistration(mockf200.teeAddress); - WorkloadId baseWorkloadId = policy.workloadIdForTDRegistration(baseRegistration); - - // Test that all combinations of allowed bits don't affect workloadId - // We test: none set, all set, and one intermediate case - bytes8[3] memory allowedBitCombos = [ - bytes8(0x00000000D0000000), // All three allowed bits set (VE_DISABLED | PKS | KL) - bytes8(0x0000000050000000), // VE_DISABLED | PKS - bytes8(0x0000000000000000) // None set - ]; - - for (uint256 i = 0; i < allowedBitCombos.length; i++) { - IFlashtestationRegistry.RegisteredTEE memory modifiedRegAllowed = baseRegistration; - // Clear the allowed bits first, then set the specific combination - modifiedRegAllowed.parsedReportBody.tdAttributes = - (baseRegistration.parsedReportBody.tdAttributes & ~bytes8(0x00000000D0000000)) | allowedBitCombos[i]; - - WorkloadId workloadId = policy.workloadIdForTDRegistration(modifiedRegAllowed); - assertEq( - WorkloadId.unwrap(baseWorkloadId), - WorkloadId.unwrap(workloadId), - "Allowed tdAttributes bits should not affect workloadId" - ); - } - - // Test that a non-allowed bit DOES change workloadId - IFlashtestationRegistry.RegisteredTEE memory modifiedReg = baseRegistration; - modifiedReg.parsedReportBody.tdAttributes = - baseRegistration.parsedReportBody.tdAttributes | bytes8(0x0000000000000001); - WorkloadId differentWorkloadId = policy.workloadIdForTDRegistration(modifiedReg); - assertNotEq( - WorkloadId.unwrap(baseWorkloadId), - WorkloadId.unwrap(differentWorkloadId), - "Non-allowed tdAttributes bits should affect workloadId" - ); - } - - function test_workloadId_xfam_expected_bits_required() public { - // Register a TEE to get a baseline - _registerTEE(mockf200); - (, IFlashtestationRegistry.RegisteredTEE memory baseRegistration) = - registry.getRegistration(mockf200.teeAddress); - WorkloadId baseWorkloadId = policy.workloadIdForTDRegistration(baseRegistration); - - // Test removing FPU bit changes workloadId - IFlashtestationRegistry.RegisteredTEE memory modifiedReg1 = baseRegistration; - modifiedReg1.parsedReportBody.xFAM = baseRegistration.parsedReportBody.xFAM ^ bytes8(0x0000000000000001); - WorkloadId workloadIdNoFPU = policy.workloadIdForTDRegistration(modifiedReg1); - assertNotEq( - WorkloadId.unwrap(baseWorkloadId), - WorkloadId.unwrap(workloadIdNoFPU), - "Missing FPU bit should change workloadId" - ); - - // Test removing SSE bit changes workloadId - IFlashtestationRegistry.RegisteredTEE memory modifiedReg2 = baseRegistration; - modifiedReg2.parsedReportBody.xFAM = baseRegistration.parsedReportBody.xFAM ^ bytes8(0x0000000000000002); - WorkloadId workloadIdNoSSE = policy.workloadIdForTDRegistration(modifiedReg2); - assertNotEq( - WorkloadId.unwrap(baseWorkloadId), - WorkloadId.unwrap(workloadIdNoSSE), - "Missing SSE bit should change workloadId" - ); - - // Test adding an extra bit changes workloadId - IFlashtestationRegistry.RegisteredTEE memory modifiedReg3 = baseRegistration; - modifiedReg3.parsedReportBody.xFAM = baseRegistration.parsedReportBody.xFAM | bytes8(0x0000000000000008); - WorkloadId workloadIdExtraBit = policy.workloadIdForTDRegistration(modifiedReg3); - assertNotEq( - WorkloadId.unwrap(baseWorkloadId), - WorkloadId.unwrap(workloadIdExtraBit), - "Additional xFAM bits should change workloadId" - ); - } - function test_verifyBlockBuilderProof_fails_with_unregistered_tee() public { // Add workload to policy but don't register TEE policy.addWorkloadToPolicy(mockf200.workloadId, mockf200.commitHash, mockf200.sourceLocators);