-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathTEELivenessVerifier.sol
160 lines (126 loc) · 5.53 KB
/
TEELivenessVerifier.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.12;
import {IAttestationVerifier} from "../interfaces/IAttestationVerifier.sol";
import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol";
contract TEELivenessVerifier is OwnableUpgradeable {
struct Pubkey {
bytes32 x;
bytes32 y;
}
struct Prover {
Pubkey pubkey;
uint256 time;
}
struct ReportDataV2 {
Pubkey pubkey;
uint256 referenceBlockNumber;
bytes32 referenceBlockHash;
bytes32 proverAddressHash;
}
error INVALID_REPORT();
error INVALID_REPORT_DATA();
error REPORT_DATA_MISMATCH(bytes);
mapping(bytes32 => bool) public attestedReports;
mapping(bytes32 => Prover) public attestedProvers; // prover's pubkey => attestedTime
uint256 public attestValiditySeconds = 3600;
IAttestationVerifier public attestationVerifier;
// added at v2
uint256 public maxBlockNumberDiff;
mapping(bytes32 proverKey => address proverAddr) public attestedProverAddr;
constructor() {
_disableInitializers();
}
function initialize(
address _initialOwner,
address _attestationAddr,
uint256 _maxBlockNumberDiff,
uint256 _attestValiditySeconds
) public initializer {
attestationVerifier = IAttestationVerifier(_attestationAddr);
maxBlockNumberDiff = _maxBlockNumberDiff;
attestValiditySeconds = _attestValiditySeconds;
_transferOwnership(_initialOwner);
}
function reinitialize(
uint8 i,
address _initialOwner,
address _attestationAddr,
uint256 _maxBlockNumberDiff,
uint256 _attestValiditySeconds
) public reinitializer(i) {
attestationVerifier = IAttestationVerifier(_attestationAddr);
maxBlockNumberDiff = _maxBlockNumberDiff;
attestValiditySeconds = _attestValiditySeconds;
_transferOwnership(_initialOwner);
}
function changeMaxBlockNumberDiff(uint256 _maxBlockNumberDiff) public onlyOwner {
maxBlockNumberDiff = _maxBlockNumberDiff;
}
function changeAttestationImpl(address _attestationAddr) public onlyOwner {
attestationVerifier = IAttestationVerifier(_attestationAddr);
}
function changeAttestValiditySeconds(uint256 val) public onlyOwner {
attestValiditySeconds = val;
}
function verifyMrEnclave(bytes32 _mrenclave) public view returns (bool) {
return attestationVerifier.verifyMrEnclave(_mrenclave);
}
function verifyMrSigner(bytes32 _mrsigner) public view returns (bool) {
return attestationVerifier.verifyMrSigner(_mrsigner);
}
function submitLivenessProofV2(ReportDataV2 calldata _data, bytes calldata _report) public payable {
checkBlockNumber(_data.referenceBlockNumber, _data.referenceBlockHash);
bytes32 dataHash = keccak256(abi.encode(_data));
(bytes memory reportData) = attestationVerifier.verifyAttestation{value: msg.value}(_report);
bytes32 reportHash = keccak256(_report);
require(!attestedReports[reportHash], "report is already used");
(bytes32 proverBytes, bytes32 reportDataHash) = splitBytes64(reportData);
if (dataHash != reportDataHash) {
revert REPORT_DATA_MISMATCH(reportData);
}
Prover memory prover = Prover(_data.pubkey, block.timestamp);
bytes32 proverKey = keccak256(abi.encode(_data.pubkey.x, _data.pubkey.y));
attestedProvers[proverKey] = prover;
attestedProverAddr[proverKey] = address(uint160(uint256(proverBytes)));
attestedReports[reportHash] = true;
}
function verifyLivenessProof(bytes32 pubkeyX, bytes32 pubkeyY) public view returns (bool) {
bytes32 signer = keccak256(abi.encode(pubkeyX, pubkeyY));
return attestedProvers[signer].time + attestValiditySeconds > block.timestamp;
}
function verifyLivenessProofV2(bytes32 pubkeyX, bytes32 pubkeyY, address proverKey) public view returns (bool) {
bytes32 signer = keccak256(abi.encode(pubkeyX, pubkeyY));
bool succ = attestedProvers[signer].time + attestValiditySeconds > block.timestamp;
if (!succ) {
return false;
}
return attestedProverAddr[signer] == proverKey;
}
function verifyAttestationV2(bytes32 pubkeyX, bytes32 pubkeyY, bytes calldata data) public returns (bool) {
bytes memory reportData = attestationVerifier.verifyAttestation(data);
(bytes32 x, bytes32 y) = splitBytes64(reportData);
if (x != pubkeyX || y != pubkeyY) {
return false;
}
return true;
}
function splitBytes64(bytes memory b) private pure returns (bytes32, bytes32) {
require(b.length >= 64, "Bytes array too short");
bytes32 x;
bytes32 y;
assembly {
x := mload(add(b, 32))
y := mload(add(b, 64))
}
return (x, y);
}
// this function will make sure the attestation report generated in recent ${maxBlockNumberDiff} blocks
function checkBlockNumber(uint256 blockNumber, bytes32 blockHash) private view {
require(blockNumber < block.number, "invalid block number");
require(block.number - blockNumber < maxBlockNumberDiff, "block number out-of-date");
require(blockhash(blockNumber) == blockHash, "block number mismatch");
}
function estimateBaseFeeVerifyOnChain(bytes calldata rawQuote) external payable returns (uint256) {
return attestationVerifier.estimateBaseFeeVerifyOnChain{value: msg.value}(rawQuote);
}
}