Skip to content

Commit 20a721f

Browse files
committed
add latest_tcb_evalulation_data_number and allow_previous_tcb_evalulation_data_number to client state of the LCP client
Signed-off-by: Jun Kimura <jun.kimura@datachain.jp>
1 parent 0a9aec4 commit 20a721f

File tree

5 files changed

+177
-54
lines changed

5 files changed

+177
-54
lines changed

modules/lcp-client/src/client_def.rs

Lines changed: 51 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use attestation_report::{IASSignedReport, ReportData};
1010
use crypto::{verify_signature_address, Address, Keccak256};
1111
use dcap_quote_verifier::types::quotes::body::QuoteBody;
1212
use dcap_quote_verifier::types::SGX_TEE_TYPE;
13+
use dcap_quote_verifier::verifier::Status;
1314
use hex_literal::hex;
1415
use light_client::commitments::{
1516
CommitmentPrefix, EthABIEncoder, MisbehaviourProxyMessage, ProxyMessage,
@@ -246,52 +247,72 @@ impl LCPClient {
246247
let zkdcap_verifier_info = &client_state.zkdcap_verifier_infos[0];
247248
assert!(message.zkvm_type == ZKVMType::Risc0);
248249
let (selector, seal) = message.risc0_seal_selector()?;
250+
let output = message.quote_verification_output;
249251

250252
zkvm::verifier::verify_groth16_proof(
251253
selector,
252254
seal,
253255
zkdcap_verifier_info.program_id,
254-
message.quote_verification_output.to_bytes(),
256+
output.to_bytes(),
255257
)?;
256258

257-
let report =
258-
if let QuoteBody::SGXQuoteBody(report) = message.quote_verification_output.quote_body {
259-
report
260-
} else {
261-
return Err(Error::unexpected_quote_body());
262-
};
259+
let report = if let QuoteBody::SGXQuoteBody(report) = output.quote_body {
260+
report
261+
} else {
262+
return Err(Error::unexpected_quote_body());
263+
};
263264
let report_data = ReportData(report.report_data);
264265

265266
assert_eq!(
266267
report.mrenclave.as_slice(),
267268
client_state.mr_enclave.as_slice(),
268269
"mrenclave mismatch"
269270
);
271+
assert_eq!(output.quote_version, 3, "unexpected quote version");
272+
assert_eq!(output.tee_type, SGX_TEE_TYPE, "unexpected tee type");
270273
assert_eq!(
271-
message.quote_verification_output.quote_version, 3,
272-
"unexpected quote version"
273-
);
274-
assert_eq!(
275-
message.quote_verification_output.tee_type, SGX_TEE_TYPE,
276-
"unexpected tee type"
277-
);
278-
assert_eq!(
279-
message.quote_verification_output.sgx_intel_root_ca_hash,
274+
output.sgx_intel_root_ca_hash,
280275
remote_attestation::dcap::INTEL_ROOT_CA_HASH,
281276
);
277+
278+
#[allow(clippy::comparison_chain)]
279+
#[allow(clippy::assertions_on_constants)]
280+
let new_client_state = if client_state.latest_tcb_evaluation_data_number
281+
< output.min_tcb_evaluation_data_number
282+
{
283+
Some(ClientState {
284+
latest_tcb_evaluation_data_number: output.min_tcb_evaluation_data_number,
285+
..client_state.clone()
286+
})
287+
} else if client_state.latest_tcb_evaluation_data_number
288+
> output.min_tcb_evaluation_data_number
289+
{
290+
if !client_state.allow_previous_tcb_evaluation_data_number
291+
|| client_state.latest_tcb_evaluation_data_number
292+
!= output.min_tcb_evaluation_data_number + 1
293+
{
294+
assert!(false, "unexpected tcb evaluation data number");
295+
}
296+
None
297+
} else {
298+
None
299+
};
300+
282301
assert!(
283-
message
284-
.quote_verification_output
302+
output
285303
.validity
286304
.validate_time(ctx.host_timestamp().as_unix_timestamp_secs()),
287305
"invalid validity intersection"
288306
);
289-
let tcb_status = message.quote_verification_output.status.to_string();
307+
290308
assert!(
291-
tcb_status == "UpToDate" || client_state.allowed_quote_statuses.contains(&tcb_status),
309+
output.status == Status::Ok
310+
|| client_state
311+
.allowed_quote_statuses
312+
.contains(&output.status.to_string()),
292313
"unexpected tcb status"
293314
);
294-
for advisory_id in message.quote_verification_output.advisory_ids.iter() {
315+
for advisory_id in output.advisory_ids.iter() {
295316
assert!(
296317
client_state.allowed_advisory_ids.contains(advisory_id),
297318
"unexpected advisory id"
@@ -302,7 +323,7 @@ impl LCPClient {
302323
verify_signature_address(
303324
compute_eip712_zkdcap_register_enclave_key(
304325
zkdcap_verifier_info,
305-
keccak256(&message.quote_verification_output.to_bytes()),
326+
keccak256(&output.to_bytes()),
306327
)
307328
.as_ref(),
308329
operator_signature.as_ref(),
@@ -317,11 +338,11 @@ impl LCPClient {
317338
ctx,
318339
&client_id,
319340
report_data.enclave_key(),
320-
EKOperatorInfo::new(
321-
message.quote_verification_output.validity.not_after_min,
322-
operator,
323-
),
341+
EKOperatorInfo::new(output.validity.not_after_min, operator),
324342
);
343+
if let Some(new_client_state) = new_client_state {
344+
ctx.store_any_client_state(client_id, new_client_state.into())?;
345+
}
325346
Ok(())
326347
}
327348

@@ -566,16 +587,16 @@ pub fn compute_eip712_register_enclave_key_hash(avr: &str) -> [u8; 32] {
566587

567588
pub fn compute_eip712_zkdcap_register_enclave_key(
568589
zkdcap_verifier_info: &ZKDCAPVerifierInfo,
569-
commit_hash: [u8; 32],
590+
output_hash: [u8; 32],
570591
) -> Vec<u8> {
571-
// 0x1901 | DOMAIN_SEPARATOR_ZKDCAP_REGISTER_ENCLAVE_KEY | keccak256(keccak256("ZKDCAPRegisterEnclaveKey(bytes zkDCAPVerifierInfo,bytes32 commitHash)") | keccak256(zkdcap_verifier_info) | commit_hash)
592+
// 0x1901 | DOMAIN_SEPARATOR_ZKDCAP_REGISTER_ENCLAVE_KEY | keccak256(keccak256("ZKDCAPRegisterEnclaveKey(bytes zkDCAPVerifierInfo,bytes32 outputHash)") | keccak256(zkdcap_verifier_info) | output_hash)
572593
let type_hash = {
573594
let mut h = Keccak::v256();
574595
h.update(&keccak256(
575-
b"ZKDCAPRegisterEnclaveKey(bytes zkDCAPVerifierInfo,bytes32 commitHash)",
596+
b"ZKDCAPRegisterEnclaveKey(bytes zkDCAPVerifierInfo,bytes32 outputHash)",
576597
));
577598
h.update(&keccak256(zkdcap_verifier_info.to_bytes().as_ref()));
578-
h.update(&commit_hash);
599+
h.update(&output_hash);
579600
let mut result = [0u8; 32];
580601
h.finalize(result.as_mut());
581602
result

modules/lcp-client/src/client_state.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ pub struct ClientState {
2828
pub operators_nonce: u64,
2929
pub operators_threshold_numerator: u64,
3030
pub operators_threshold_denominator: u64,
31+
pub latest_tcb_evaluation_data_number: u32,
32+
pub allow_previous_tcb_evaluation_data_number: bool,
3133
pub zkdcap_verifier_infos: Vec<ZKDCAPVerifierInfo>,
3234
}
3335

@@ -131,6 +133,9 @@ impl From<ClientState> for RawClientState {
131133
operators_nonce: 0,
132134
operators_threshold_numerator: 0,
133135
operators_threshold_denominator: 0,
136+
latest_tcb_evalulation_data_number: value.latest_tcb_evaluation_data_number,
137+
allow_previous_tcb_evalulation_data_number: value
138+
.allow_previous_tcb_evaluation_data_number,
134139
zkdcap_verifier_infos: value
135140
.zkdcap_verifier_infos
136141
.iter()
@@ -160,6 +165,9 @@ impl TryFrom<RawClientState> for ClientState {
160165
operators_nonce: raw.operators_nonce,
161166
operators_threshold_numerator: raw.operators_threshold_numerator,
162167
operators_threshold_denominator: raw.operators_threshold_denominator,
168+
latest_tcb_evaluation_data_number: raw.latest_tcb_evalulation_data_number,
169+
allow_previous_tcb_evaluation_data_number: raw
170+
.allow_previous_tcb_evalulation_data_number,
163171
zkdcap_verifier_infos: raw
164172
.zkdcap_verifier_infos
165173
.into_iter()

proto/definitions/ibc/lightclients/lcp/v1/lcp.proto

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,61 +8,107 @@ option go_package = "github.com/datachainlab/lcp/go/light-clients/lcp/types";
88
option (gogoproto.goproto_getters_all) = false;
99

1010
message UpdateClientMessage {
11+
// A message generated by the LCP node running on the target platform
1112
bytes proxy_message = 1;
13+
// Signatures of the proxy message by the LCP node
1214
repeated bytes signatures = 2;
1315
}
1416

17+
// A message to verify IAS report and signature for the enclave key registration
1518
message RegisterEnclaveKeyMessage {
19+
// IAS report
1620
bytes report = 1;
21+
// A signature of the IAS report by the IAS signing key
1722
bytes signature = 2;
23+
// A certificate of the IAS signing key
1824
bytes signing_cert = 3;
25+
// An operator's signature of the EIP-712 message `RegisterEnclaveKey`
1926
bytes operator_signature = 4;
2027
}
2128

29+
// A message to verify zkDCAP output and proof for the enclave key registration
2230
message ZKDCAPRegisterEnclaveKeyMessage {
31+
// A type of zkVM generated the `quote_verification_output` and `proof`
2332
uint32 zkvm_type = 1;
33+
// An output of the zkDCAP program that verifies the quote
2434
bytes quote_verification_output = 2;
35+
// A proof of the zkVM generated the `quote_verification_output`
2536
bytes proof = 3;
37+
// An operator's signature of the EIP-712 message `ZKDCAPRegisterEnclaveKey`
2638
bytes operator_signature = 4;
2739
}
2840

2941
message UpdateOperatorsMessage {
42+
// A nonce for this operators update
3043
uint64 nonce = 1;
44+
// A list of new operators
3145
repeated bytes new_operators = 2;
46+
// A numerator of the threshold of signatures required for new operators
3247
uint64 new_operators_threshold_numerator = 3;
48+
// A denominator of the threshold of signatures required for new operators
3349
uint64 new_operators_threshold_denominator = 4;
50+
// Signatures of the EIP-712 message `UpdateOperators` by the current operators
3451
repeated bytes signatures = 5;
3552
}
3653

3754
message ClientState {
55+
// The MRENCLAVE of the enclave in running on the target platform
3856
bytes mrenclave = 1;
39-
// enclave key's expiration from the remote attestation time in seconds
57+
// An enclave key's expiration period from the remote attestation time in seconds
4058
//
41-
// If the key is got from the DCAP/zkDCAP's quote, it should be the collateral's expiration time instead.
59+
// This is only used for the IAS.
4260
uint64 key_expiration = 2;
61+
// Whether the client is frozen
4362
bool frozen = 3;
63+
// The height of the latest consensus state that the client has tracked
4464
ibc.core.client.v1.Height latest_height = 4 [(gogoproto.nullable) = false];
45-
// e.g. SW_HARDENING_NEEDED, CONFIGURATION_AND_SW_HARDENING_NEEDED (except "OK")
65+
// The quote statuses of the target enclave that the client allows
66+
//
67+
// e.g. IAS: SW_HARDENING_NEEDED, CONFIGURATION_AND_SW_HARDENING_NEEDED
68+
// DCAP: SWHardeningNeeded, ConfigurationAndSWHardeningNeeded
4669
repeated string allowed_quote_statuses = 5;
47-
// e.g. INTEL-SA-XXXXX
70+
// Security Advisory IDs that the client allows
71+
//
72+
// e.g. INTEL-SA-00001, INTEL-SA-00002
4873
repeated string allowed_advisory_ids = 6;
74+
// A list of addresses of LCP Operators corresponding to this client.
75+
//
76+
// Please check LCP operator details: <https://docs.lcp.network/protocol/lcp-client#lcp-operator>
4977
repeated bytes operators = 7;
78+
// A current nonce for the operators update
5079
uint64 operators_nonce = 8;
80+
// The numerator of the threshold of the signature number for the operators update
5181
uint64 operators_threshold_numerator = 9;
82+
// The denominator of the threshold of the signature number for the operators update
5283
uint64 operators_threshold_denominator = 10;
53-
// An optional field to store the verifier info for zkDCAP
84+
// The latest TCB evaluation data number
85+
//
86+
// The client updates the number when receiving TCB evaluation data whose number is greater than the current number.
87+
uint32 latest_tcb_evalulation_data_number = 11;
88+
// Whether to allow the previous TCB evaluation data number
5489
//
55-
// if empty, the zkDCAP is not enabled
56-
// otherwise, the zkDCAP is enabled
57-
// The layout of each element is as follows:
58-
// 0: zkVM type (e.g. 1 for risc0)
59-
// 1-31: reserved
60-
// 32-64: guest program identifier
61-
repeated bytes zkdcap_verifier_infos = 11;
90+
// If this is true, the client will accept the previous TCB evaluation data number (i.e., `latest_tcb_evalulation_data_number` - 1).
91+
// Otherwise, the client will only accept the latest TCB evaluation data number or greater.
92+
bool allow_previous_tcb_evalulation_data_number = 12;
93+
// The zkVM 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+
// zkVM type:
100+
// 0: unspecified
101+
// 1: risc0
102+
repeated bytes zkdcap_verifier_infos = 14;
62103
}
63104

64105
message ConsensusState {
106+
// An identifier that uniquely indicates the state of the ELC corresponding to a certain height.
107+
//
108+
// Please check the state ID details: <https://docs.lcp.network/protocol/elc#state-id>
65109
bytes state_id = 1;
110+
// A timestamp of the target chain's block corresponding to the consensus height
111+
//
66112
// unix timestamp in seconds
67113
uint64 timestamp = 2;
68114
}

proto/src/descriptor.bin

2.54 KB
Binary file not shown.

0 commit comments

Comments
 (0)