Skip to content

Commit b731bc9

Browse files
committed
add latest_tcb_eval_data_num and allow_non_latest_tcb_eval_data_num to client state
Signed-off-by: Jun Kimura <jun.kimura@datachain.jp>
1 parent c2e7084 commit b731bc9

File tree

5 files changed

+201
-40
lines changed

5 files changed

+201
-40
lines changed

contracts/DCAPValidator.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ library DCAPValidator {
4848
*/
4949
struct Output {
5050
string tcbStatus;
51+
uint32 minTcbEvaluationDataNumber;
5152
bytes32 sgxIntelRootCAHash;
5253
uint64 validityNotBeforeMax;
5354
uint64 validityNotAfterMin;
@@ -70,6 +71,7 @@ library DCAPValidator {
7071

7172
Output memory output;
7273
output.tcbStatus = tcbStatusToString(uint8(outputBytes[8]));
74+
output.minTcbEvaluationDataNumber = uint32(bytes4(outputBytes[9:13]));
7375
output.sgxIntelRootCAHash = bytes32(outputBytes[19:51]);
7476
output.validityNotBeforeMax = uint64(bytes8(outputBytes[51:59]));
7577
output.validityNotAfterMin = uint64(bytes8(outputBytes[59:67]));

contracts/ILCPClientErrors.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ interface ILCPClientErrors {
6262
error LCPClientZKDCAPInvalidConstructorParams();
6363
error LCPClientZKDCAPOutputNotValid();
6464
error LCPClientZKDCAPUnrecognizedTCBStatus();
65+
error LCPClientZKDCAPLatestTcbEvaluationDataNumberNotSet();
6566
error LCPClientZKDCAPInvalidVerifierInfos();
6667
error LCPClientZKDCAPInvalidVerifierInfoLength();
6768
error LCPClientZKDCAPInvalidVerifierInfoZKVMType();
@@ -72,4 +73,5 @@ interface ILCPClientErrors {
7273
error LCPClientZKDCAPDisallowedTCBStatus();
7374
error LCPClientZKDCAPDisallowedAdvisoryID();
7475
error LCPClientZKDCAPUnexpectedEnclaveDebugMode();
76+
error LCPClientZKDCAPUnexpectedTcbEvaluationDataNumber();
7577
}

contracts/LCPClientZKDCAPBase.sol

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ abstract contract LCPClientZKDCAPBase is LCPClientBase {
2222

2323
// --------------------- Events ---------------------
2424

25-
event ZKDCAPRegisteredEnclaveKey(string clientId, address enclaveKey, uint256 expiredAt, address operator);
25+
/// @dev Emitted when an enclave key from zkDCAP quote is registered.
26+
event LCPClientZKDCAPRegisteredEnclaveKey(string clientId, address enclaveKey, uint256 expiredAt, address operator);
27+
28+
/// @dev Emitted when the latest TCB evaluation data number is updated.
29+
event LCPClientZKDCAPUpdateLatestTcbEvaluationDataNumber(string clientId, uint32 tcbEvaluationDataNumber);
2630

2731
// --------------------- Immutable fields ---------------------
2832

@@ -74,23 +78,45 @@ abstract contract LCPClientZKDCAPBase is LCPClientBase {
7478
ClientStorage storage clientStorage = clientStorages[clientId];
7579
(ProtoClientState.Data memory clientState,) =
7680
_initializeClient(clientStorage, protoClientState, protoConsensusState);
81+
if (clientState.latest_tcb_evalulation_data_number == 0) {
82+
revert LCPClientZKDCAPLatestTcbEvaluationDataNumberNotSet();
83+
}
7784
if (clientState.zkdcap_verifier_infos.length != 1) {
7885
revert LCPClientZKDCAPInvalidVerifierInfos();
7986
}
80-
bytes memory verifierInfo = clientState.zkdcap_verifier_infos[0];
81-
if (verifierInfo.length != 64) {
87+
// Currently, the client only supports RISC Zero zkVM
88+
clientStorage.zkDCAPRisc0ImageId = parseRiscZeroVerifierInfo(clientState.zkdcap_verifier_infos[0]);
89+
return clientState.latest_height;
90+
}
91+
92+
function parseRiscZeroVerifierInfo(bytes memory verifierInfo) internal pure returns (bytes32) {
93+
// The verifier information for the zkDCAP
94+
//
95+
// The format is as follows:
96+
// 0: zkVM type
97+
// 1-N: arbitrary data for each zkVM type
98+
//
99+
// The format of the risc0 zkVM is as follows:
100+
// | 0 | 1 - 31 | 32 - 64 |
101+
// |---|----------|-----------|
102+
// | 1 | reserved | image id |
103+
uint256 vlen = verifierInfo.length;
104+
if (vlen == 0) {
82105
revert LCPClientZKDCAPInvalidVerifierInfoLength();
83106
}
107+
// Currently, the client only supports RISC Zero zkVM
84108
if (uint8(verifierInfo[0]) != ZKVM_TYPE_RISC_ZERO) {
85109
revert LCPClientZKDCAPInvalidVerifierInfoZKVMType();
86110
}
111+
if (vlen < 64) {
112+
revert LCPClientZKDCAPInvalidVerifierInfoLength();
113+
}
87114
// 32..64 bytes: image ID
88115
bytes32 imageId;
89116
assembly {
90117
imageId := mload(add(add(verifierInfo, 32), 32))
91118
}
92-
clientStorage.zkDCAPRisc0ImageId = imageId;
93-
return clientState.latest_height;
119+
return imageId;
94120
}
95121

96122
/**
@@ -131,6 +157,7 @@ abstract contract LCPClientZKDCAPBase is LCPClientBase {
131157
if (clientStorage.zkDCAPRisc0ImageId == bytes32(0)) {
132158
revert LCPClientZKDCAPRisc0ImageIdNotSet();
133159
}
160+
ProtoClientState.Data storage clientState = clientStorage.clientState;
134161
// NOTE: the client must revert if the proof is invalid
135162
riscZeroVerifier.verify(
136163
message.proof, clientStorage.zkDCAPRisc0ImageId, sha256(message.quote_verification_output)
@@ -139,7 +166,7 @@ abstract contract LCPClientZKDCAPBase is LCPClientBase {
139166
if (output.sgxIntelRootCAHash != intelRootCAHash) {
140167
revert LCPClientZKDCAPUnexpectedIntelRootCAHash();
141168
}
142-
if (output.mrenclave != bytes32(clientStorage.clientState.mrenclave)) {
169+
if (output.mrenclave != bytes32(clientState.mrenclave)) {
143170
revert LCPClientClientStateUnexpectedMrenclave();
144171
}
145172

@@ -162,23 +189,38 @@ abstract contract LCPClientZKDCAPBase is LCPClientBase {
162189
}
163190
}
164191

165-
// check if the `output.enclaveDebugEnabled` and `developmentMode` are consistent
166-
if (output.enclaveDebugEnabled != developmentMode) {
167-
revert LCPClientZKDCAPUnexpectedEnclaveDebugMode();
192+
if (clientState.latest_tcb_evalulation_data_number < output.minTcbEvaluationDataNumber) {
193+
clientState.latest_tcb_evalulation_data_number = output.minTcbEvaluationDataNumber;
194+
heights = new Height.Data[](1);
195+
heights[0] = clientState.latest_height;
196+
emit LCPClientZKDCAPUpdateLatestTcbEvaluationDataNumber(clientId, output.minTcbEvaluationDataNumber);
197+
} else if (clientState.latest_tcb_evalulation_data_number > output.minTcbEvaluationDataNumber) {
198+
// NOTE: if the client allows previous TCB evaluation data number, the client should only accept the previous number
199+
if (
200+
!clientState.allow_previous_tcb_evalulation_data_number
201+
|| clientState.latest_tcb_evalulation_data_number != output.minTcbEvaluationDataNumber + 1
202+
) {
203+
revert LCPClientZKDCAPUnexpectedTcbEvaluationDataNumber();
204+
}
168205
}
169206

170207
// check if the validity period of the output is valid at the current block timestamp
171208
if (block.timestamp < output.validityNotBeforeMax || block.timestamp > output.validityNotAfterMin) {
172209
revert LCPClientZKDCAPOutputNotValid();
173210
}
174211

212+
// check if the `output.enclaveDebugEnabled` and `developmentMode` are consistent
213+
if (output.enclaveDebugEnabled != developmentMode) {
214+
revert LCPClientZKDCAPUnexpectedEnclaveDebugMode();
215+
}
216+
175217
// if `operator_signature` is empty, the operator address is zero
176218
address operator;
177219
if (message.operator_signature.length != 0) {
178220
operator = verifyECDSASignature(
179221
keccak256(
180222
LCPOperator.computeEIP712ZKDCAPRegisterEnclaveKey(
181-
clientStorage.clientState.zkdcap_verifier_infos[0], keccak256(message.quote_verification_output)
223+
clientState.zkdcap_verifier_infos[0], keccak256(message.quote_verification_output)
182224
)
183225
),
184226
message.operator_signature
@@ -197,15 +239,13 @@ abstract contract LCPClientZKDCAPBase is LCPClientBase {
197239
if (ekInfo.expiredAt != expiredAt) {
198240
revert LCPClientEnclaveKeyUnexpectedExpiredAt();
199241
}
200-
// NOTE: if the key already exists, don't update any state
201242
return heights;
202243
}
203244
ekInfo.expiredAt = expiredAt;
204245
ekInfo.operator = operator;
205246

206-
emit ZKDCAPRegisteredEnclaveKey(clientId, output.enclaveKey, expiredAt, operator);
247+
emit LCPClientZKDCAPRegisteredEnclaveKey(clientId, output.enclaveKey, expiredAt, operator);
207248

208-
// Note: client and consensus state are not always updated in registerEnclaveKey
209249
return heights;
210250
}
211251
}

contracts/proto/ibc/lightclients/lcp/v1/LCP.sol

Lines changed: 84 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1440,6 +1440,8 @@ library IbcLightclientsLcpV1ClientState {
14401440
uint64 operators_nonce;
14411441
uint64 operators_threshold_numerator;
14421442
uint64 operators_threshold_denominator;
1443+
uint32 latest_tcb_evalulation_data_number;
1444+
bool allow_previous_tcb_evalulation_data_number;
14431445
bytes[] zkdcap_verifier_infos;
14441446
}
14451447

@@ -1480,7 +1482,7 @@ library IbcLightclientsLcpV1ClientState {
14801482
returns (Data memory, uint)
14811483
{
14821484
Data memory r;
1483-
uint[12] memory counters;
1485+
uint[15] memory counters;
14841486
uint256 fieldId;
14851487
ProtoBufRuntime.WireType wireType;
14861488
uint256 bytesRead;
@@ -1520,6 +1522,12 @@ library IbcLightclientsLcpV1ClientState {
15201522
pointer += _read_operators_threshold_denominator(pointer, bs, r);
15211523
} else
15221524
if (fieldId == 11) {
1525+
pointer += _read_latest_tcb_evalulation_data_number(pointer, bs, r);
1526+
} else
1527+
if (fieldId == 12) {
1528+
pointer += _read_allow_previous_tcb_evalulation_data_number(pointer, bs, r);
1529+
} else
1530+
if (fieldId == 14) {
15231531
pointer += _read_unpacked_repeated_zkdcap_verifier_infos(pointer, bs, nil(), counters);
15241532
} else
15251533
{
@@ -1540,9 +1548,9 @@ library IbcLightclientsLcpV1ClientState {
15401548
require(r.operators.length == 0);
15411549
r.operators = new bytes[](counters[7]);
15421550
}
1543-
if (counters[11] > 0) {
1551+
if (counters[14] > 0) {
15441552
require(r.zkdcap_verifier_infos.length == 0);
1545-
r.zkdcap_verifier_infos = new bytes[](counters[11]);
1553+
r.zkdcap_verifier_infos = new bytes[](counters[14]);
15461554
}
15471555

15481556
while (pointer < offset + sz) {
@@ -1557,7 +1565,7 @@ library IbcLightclientsLcpV1ClientState {
15571565
if (fieldId == 7) {
15581566
pointer += _read_unpacked_repeated_operators(pointer, bs, r, counters);
15591567
} else
1560-
if (fieldId == 11) {
1568+
if (fieldId == 14) {
15611569
pointer += _read_unpacked_repeated_zkdcap_verifier_infos(pointer, bs, r, counters);
15621570
} else
15631571
{
@@ -1649,7 +1657,7 @@ library IbcLightclientsLcpV1ClientState {
16491657
uint256 p,
16501658
bytes memory bs,
16511659
Data memory r,
1652-
uint[12] memory counters
1660+
uint[15] memory counters
16531661
) internal pure returns (uint) {
16541662
/**
16551663
* if `r` is NULL, then only counting the number of fields.
@@ -1676,7 +1684,7 @@ library IbcLightclientsLcpV1ClientState {
16761684
uint256 p,
16771685
bytes memory bs,
16781686
Data memory r,
1679-
uint[12] memory counters
1687+
uint[15] memory counters
16801688
) internal pure returns (uint) {
16811689
/**
16821690
* if `r` is NULL, then only counting the number of fields.
@@ -1703,7 +1711,7 @@ library IbcLightclientsLcpV1ClientState {
17031711
uint256 p,
17041712
bytes memory bs,
17051713
Data memory r,
1706-
uint[12] memory counters
1714+
uint[15] memory counters
17071715
) internal pure returns (uint) {
17081716
/**
17091717
* if `r` is NULL, then only counting the number of fields.
@@ -1769,6 +1777,40 @@ library IbcLightclientsLcpV1ClientState {
17691777
return sz;
17701778
}
17711779

1780+
/**
1781+
* @dev The decoder for reading a field
1782+
* @param p The offset of bytes array to start decode
1783+
* @param bs The bytes array to be decoded
1784+
* @param r The in-memory struct
1785+
* @return The number of bytes decoded
1786+
*/
1787+
function _read_latest_tcb_evalulation_data_number(
1788+
uint256 p,
1789+
bytes memory bs,
1790+
Data memory r
1791+
) internal pure returns (uint) {
1792+
(uint32 x, uint256 sz) = ProtoBufRuntime._decode_uint32(p, bs);
1793+
r.latest_tcb_evalulation_data_number = x;
1794+
return sz;
1795+
}
1796+
1797+
/**
1798+
* @dev The decoder for reading a field
1799+
* @param p The offset of bytes array to start decode
1800+
* @param bs The bytes array to be decoded
1801+
* @param r The in-memory struct
1802+
* @return The number of bytes decoded
1803+
*/
1804+
function _read_allow_previous_tcb_evalulation_data_number(
1805+
uint256 p,
1806+
bytes memory bs,
1807+
Data memory r
1808+
) internal pure returns (uint) {
1809+
(bool x, uint256 sz) = ProtoBufRuntime._decode_bool(p, bs);
1810+
r.allow_previous_tcb_evalulation_data_number = x;
1811+
return sz;
1812+
}
1813+
17721814
/**
17731815
* @dev The decoder for reading a field
17741816
* @param p The offset of bytes array to start decode
@@ -1781,17 +1823,17 @@ library IbcLightclientsLcpV1ClientState {
17811823
uint256 p,
17821824
bytes memory bs,
17831825
Data memory r,
1784-
uint[12] memory counters
1826+
uint[15] memory counters
17851827
) internal pure returns (uint) {
17861828
/**
17871829
* if `r` is NULL, then only counting the number of fields.
17881830
*/
17891831
(bytes memory x, uint256 sz) = ProtoBufRuntime._decode_bytes(p, bs);
17901832
if (isNil(r)) {
1791-
counters[11] += 1;
1833+
counters[14] += 1;
17921834
} else {
1793-
r.zkdcap_verifier_infos[r.zkdcap_verifier_infos.length - counters[11]] = x;
1794-
counters[11] -= 1;
1835+
r.zkdcap_verifier_infos[r.zkdcap_verifier_infos.length - counters[14]] = x;
1836+
counters[14] -= 1;
17951837
}
17961838
return sz;
17971839
}
@@ -1945,10 +1987,28 @@ library IbcLightclientsLcpV1ClientState {
19451987
);
19461988
pointer += ProtoBufRuntime._encode_uint64(r.operators_threshold_denominator, pointer, bs);
19471989
}
1990+
if (r.latest_tcb_evalulation_data_number != 0) {
1991+
pointer += ProtoBufRuntime._encode_key(
1992+
11,
1993+
ProtoBufRuntime.WireType.Varint,
1994+
pointer,
1995+
bs
1996+
);
1997+
pointer += ProtoBufRuntime._encode_uint32(r.latest_tcb_evalulation_data_number, pointer, bs);
1998+
}
1999+
if (r.allow_previous_tcb_evalulation_data_number != false) {
2000+
pointer += ProtoBufRuntime._encode_key(
2001+
12,
2002+
ProtoBufRuntime.WireType.Varint,
2003+
pointer,
2004+
bs
2005+
);
2006+
pointer += ProtoBufRuntime._encode_bool(r.allow_previous_tcb_evalulation_data_number, pointer, bs);
2007+
}
19482008
if (r.zkdcap_verifier_infos.length != 0) {
19492009
for(i = 0; i < r.zkdcap_verifier_infos.length; i++) {
19502010
pointer += ProtoBufRuntime._encode_key(
1951-
11,
2011+
14,
19522012
ProtoBufRuntime.WireType.LengthDelim,
19532013
pointer,
19542014
bs)
@@ -2015,6 +2075,8 @@ library IbcLightclientsLcpV1ClientState {
20152075
e += 1 + ProtoBufRuntime._sz_uint64(r.operators_nonce);
20162076
e += 1 + ProtoBufRuntime._sz_uint64(r.operators_threshold_numerator);
20172077
e += 1 + ProtoBufRuntime._sz_uint64(r.operators_threshold_denominator);
2078+
e += 1 + ProtoBufRuntime._sz_uint32(r.latest_tcb_evalulation_data_number);
2079+
e += 1 + 1;
20182080
for(i = 0; i < r.zkdcap_verifier_infos.length; i++) {
20192081
e += 1 + ProtoBufRuntime._sz_lendelim(r.zkdcap_verifier_infos[i].length);
20202082
}
@@ -2062,6 +2124,14 @@ library IbcLightclientsLcpV1ClientState {
20622124
return false;
20632125
}
20642126

2127+
if (r.latest_tcb_evalulation_data_number != 0) {
2128+
return false;
2129+
}
2130+
2131+
if (r.allow_previous_tcb_evalulation_data_number != false) {
2132+
return false;
2133+
}
2134+
20652135
if (r.zkdcap_verifier_infos.length != 0) {
20662136
return false;
20672137
}
@@ -2087,6 +2157,8 @@ library IbcLightclientsLcpV1ClientState {
20872157
output.operators_nonce = input.operators_nonce;
20882158
output.operators_threshold_numerator = input.operators_threshold_numerator;
20892159
output.operators_threshold_denominator = input.operators_threshold_denominator;
2160+
output.latest_tcb_evalulation_data_number = input.latest_tcb_evalulation_data_number;
2161+
output.allow_previous_tcb_evalulation_data_number = input.allow_previous_tcb_evalulation_data_number;
20902162
output.zkdcap_verifier_infos = input.zkdcap_verifier_infos;
20912163

20922164
}

0 commit comments

Comments
 (0)