Skip to content

Commit

Permalink
implement zkdcap_register_enclave_key for LCPClient
Browse files Browse the repository at this point in the history
Signed-off-by: Jun Kimura <jun.kimura@datachain.jp>
  • Loading branch information
bluele committed Dec 18, 2024
1 parent c1e32ca commit e8e9329
Show file tree
Hide file tree
Showing 13 changed files with 183 additions and 8 deletions.
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion modules/attestation-report/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ base64 = { version = "0.22.1", default-features = false, features = ["alloc"] }
pem = { version = "2.0", default-features = false }
webpki = { version = "0.22", features = ["alloc"] }

dcap-rs = { git = "https://github.com/bluele/dcap-rs", rev = "71fe1e02f151a28bf5661b01dba5096730564840", optional = true }
dcap-rs = { git = "https://github.com/bluele/dcap-rs", rev = "c3098b6a3c9faa4a884c87db65d0f586000bcf16", optional = true }

[dev-dependencies]
tokio = { version = "1.0", default-features = false, features = ["macros"] }
Expand Down
2 changes: 1 addition & 1 deletion modules/attestation-report/src/report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ impl From<DCAPQuote> for RAQuote {
/// ReportData is a 64-byte value that is embedded in the Quote
/// | version: 1 byte | enclave key: 20 bytes | operator: 20 bytes | nonce: 22 bytes |
#[derive(Debug, Clone, PartialEq)]
pub struct ReportData(pub(crate) [u8; 64]);
pub struct ReportData(pub [u8; 64]);

impl ReportData {
/// Creates a new report data
Expand Down
1 change: 1 addition & 0 deletions modules/lcp-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ flex-error = { version = "0.4.4", default-features = false }
tiny-keccak = { version = "2.0" }
hex-literal = { version = "0.4.1" }
alloy-sol-types = { version = "0.8", default-features = false }
dcap-rs = { git = "https://github.com/bluele/dcap-rs", rev = "c3098b6a3c9faa4a884c87db65d0f586000bcf16" }

attestation-report = { path = "../attestation-report", default-features = false }
light-client = { path = "../light-client", default-features = false }
Expand Down
72 changes: 69 additions & 3 deletions modules/lcp-client/src/client_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ use crate::consensus_state::ConsensusState;
use crate::errors::Error;
use crate::message::{
ClientMessage, CommitmentProofs, RegisterEnclaveKeyMessage, UpdateOperatorsMessage,
ZKDCAPRegisterEnclaveKeyMessage,
};
use alloy_sol_types::{sol, SolValue};
use attestation_report::{IASSignedReport, ReportData};
use crypto::{verify_signature_address, Address, Keccak256};
use dcap_rs::types::quotes::body::QuoteBody;
use hex_literal::hex;
use light_client::commitments::{
CommitmentPrefix, EthABIEncoder, MisbehaviourProxyMessage, ProxyMessage,
Expand Down Expand Up @@ -125,6 +127,9 @@ impl LCPClient {
ClientMessage::RegisterEnclaveKey(msg) => {
self.register_enclave_key(ctx, client_id, client_state, msg)
}
ClientMessage::ZKDCAPRegisterEnclaveKey(msg) => {
self.zkdcap_register_enclave_key(ctx, client_id, client_state, msg)
}
ClientMessage::UpdateOperators(msg) => {
self.update_operators(ctx, client_id, client_state, msg)
}
Expand Down Expand Up @@ -192,7 +197,7 @@ impl LCPClient {
assert!(!client_state.frozen);

let (report_data, attestation_time) =
verify_report(ctx.host_timestamp(), &client_state, &message.report)?;
verify_ias_report(ctx.host_timestamp(), &client_state, &message.report)?;

let operator = if let Some(operator_signature) = message.operator_signature {
verify_signature_address(
Expand All @@ -217,6 +222,50 @@ impl LCPClient {
Ok(())
}

fn zkdcap_register_enclave_key(
&self,
ctx: &mut dyn HostClientKeeper,
client_id: ClientId,
client_state: ClientState,
message: ZKDCAPRegisterEnclaveKeyMessage,
) -> Result<(), Error> {
assert!(!client_state.frozen);

// TODO
// verify_zkdcap_report(ctx.host_timestamp(), &client_state, &message.commit, &message.proof)?;

let attestation_time =
Time::from_unix_timestamp(message.commit.attestation_time as i64, 0)?;
let report = if let QuoteBody::SGXQuoteBody(report) = message.commit.output.quote_body {
report
} else {
return Err(Error::unexpected_quote_body());
};
let report_data = ReportData(report.report_data);

let operator = if let Some(operator_signature) = message.operator_signature {
verify_signature_address(
compute_eip712_zkdcap_register_enclave_key(message.commit.hash()).as_ref(),
operator_signature.as_ref(),
)?
} else {
Default::default()
};
let expected_operator = report_data.operator();
// check if the operator matches the expected operator in the report data
assert!(expected_operator.is_zero() || operator == expected_operator);
self.set_enclave_operator_info(
ctx,
&client_id,
report_data.enclave_key(),
EKOperatorInfo::new(
(attestation_time + client_state.key_expiration)?.as_unix_timestamp_secs(),
operator,
),
);
Ok(())
}

fn update_operators(
&self,
ctx: &mut dyn HostClientKeeper,
Expand Down Expand Up @@ -456,6 +505,23 @@ pub fn compute_eip712_register_enclave_key_hash(avr: &str) -> [u8; 32] {
keccak256(&compute_eip712_register_enclave_key(avr))
}

pub fn compute_eip712_zkdcap_register_enclave_key(commit_hash: [u8; 32]) -> Vec<u8> {
// 0x1901 | DOMAIN_SEPARATOR_ZKDCAP_REGISTER_ENCLAVE_KEY | keccak256(keccak256("ZKDCAPRegisterEnclaveKey(bytes32 commit_hash)") | commit_hash)
let type_hash = {
let mut h = Keccak::v256();
h.update(&keccak256(b"ZKDCAPRegisterEnclaveKey(bytes32 commit_hash)"));
h.update(&commit_hash);
let mut result = [0u8; 32];
h.finalize(result.as_mut());
result
};
[0x19, 0x01]
.into_iter()
.chain(LCP_CLIENT_DOMAIN_SEPARATOR)
.chain(type_hash)
.collect()
}

pub fn compute_eip712_update_operators(
client_id: ClientId,
nonce: u64,
Expand Down Expand Up @@ -521,10 +587,10 @@ pub fn compute_eip712_update_operators_hash(
))
}

// verify_report
// verify_ias_report
// - verifies the Attestation Verification Report
// - calculate a key expiration with client_state and report's timestamp
fn verify_report(
fn verify_ias_report(
current_timestamp: Time,
client_state: &ClientState,
signed_avr: &IASSignedReport,
Expand Down
44 changes: 44 additions & 0 deletions modules/lcp-client/src/dcap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use dcap_rs::{types::VerifiedOutput, utils::hash::keccak256sum};

#[derive(Debug, Clone, PartialEq)]
pub struct DCAPVerifierCommit {
pub output: VerifiedOutput,
pub attestation_time: u64,
pub sgx_intel_root_ca_hash: [u8; 32],
}

impl DCAPVerifierCommit {
pub fn new(attestation_time: u64, output: VerifiedOutput, sgx_intel_root_ca: &[u8]) -> Self {
Self {
attestation_time,
sgx_intel_root_ca_hash: keccak256sum(sgx_intel_root_ca),
output,
}
}

pub fn to_bytes(&self) -> Vec<u8> {
let mut output = self.output.to_bytes();
let mut aux: [u8; 40] = [0; 40];
aux[..8].copy_from_slice(&self.attestation_time.to_be_bytes());
aux[8..].copy_from_slice(&self.sgx_intel_root_ca_hash);
output.extend_from_slice(aux.as_ref());
output
}

pub fn from_bytes(slice: &[u8]) -> Self {
let output = VerifiedOutput::from_bytes(&slice[..slice.len() - 48]);
let mut attestation_time = [0; 8];
attestation_time.copy_from_slice(&slice[slice.len() - 48..slice.len() - 40]);
let mut sgx_intel_root_ca_hash = [0; 32];
sgx_intel_root_ca_hash.copy_from_slice(&slice[slice.len() - 40..]);
Self {
output,
attestation_time: u64::from_be_bytes(attestation_time),
sgx_intel_root_ca_hash,
}
}

pub fn hash(&self) -> [u8; 32] {
keccak256sum(&self.to_bytes())
}
}
5 changes: 5 additions & 0 deletions modules/lcp-client/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ define_error! {
format_args!("unexpected header type: type_url={}", e.type_url)
},

UnexpectedQuoteBody
|e| {
"unexpected quote body"
},

ExpiredAvr {
current_timestamp: light_client::types::Time,
attestation_time: light_client::types::Time,
Expand Down
1 change: 1 addition & 0 deletions modules/lcp-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ mod prelude {
pub mod client_def;
pub mod client_state;
pub mod consensus_state;
pub mod dcap;
pub mod errors;
pub mod message;
43 changes: 42 additions & 1 deletion modules/lcp-client/src/message.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,33 @@
use crate::dcap::DCAPVerifierCommit;
use crate::errors::Error;
use crate::prelude::*;
use alloy_sol_types::{sol, SolValue};
use attestation_report::IASSignedReport;
use crypto::Address;
use dcap_rs::types::VerifiedOutput;
use light_client::commitments::{Error as CommitmentError, EthABIEncoder, ProxyMessage};
use light_client::types::proto::ibc::lightclients::lcp::v1::{
RegisterEnclaveKeyMessage as RawRegisterEnclaveKeyMessage,
UpdateClientMessage as RawUpdateClientMessage,
UpdateOperatorsMessage as RawUpdateOperatorsMessage,
ZkdcapRegisterEnclaveKeyMessage as RawZKDCAPRegisterEnclaveKeyMessage,
};
use light_client::types::{proto::protobuf::Protobuf, Any};
use serde::{Deserialize, Serialize};

pub const LCP_REGISTER_ENCLAVE_KEY_MESSAGE_TYPE_URL: &str =
"/ibc.lightclients.lcp.v1.RegisterEnclaveKeyMessage";
pub const LCP_ZKDCAP_REGISTER_ENCLAVE_KEY_MESSAGE_TYPE_URL: &str =
"/ibc.lightclients.lcp.v1.ZKDCAPRegisterEnclaveKeyMessage";
pub const LCP_UPDATE_CLIENT_MESSAGE_TYPE_URL: &str = "/ibc.lightclients.lcp.v1.UpdateClientMessage";
pub const LCP_UPDATE_OPERATORS_MESSAGE_TYPE_URL: &str =
"/ibc.lightclients.lcp.v1.UpdateOperatorsMessage";

#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[derive(Debug, Clone, PartialEq)]
pub enum ClientMessage {
RegisterEnclaveKey(RegisterEnclaveKeyMessage),
ZKDCAPRegisterEnclaveKey(ZKDCAPRegisterEnclaveKeyMessage),
UpdateClient(UpdateClientMessage),
UpdateOperators(UpdateOperatorsMessage),
}
Expand Down Expand Up @@ -54,6 +60,10 @@ impl From<ClientMessage> for Any {
LCP_REGISTER_ENCLAVE_KEY_MESSAGE_TYPE_URL.to_string(),
h.encode_vec().unwrap(),
),
ClientMessage::ZKDCAPRegisterEnclaveKey(h) => Any::new(
LCP_ZKDCAP_REGISTER_ENCLAVE_KEY_MESSAGE_TYPE_URL.to_string(),
h.encode_vec().unwrap(),
),
ClientMessage::UpdateClient(h) => Any::new(
LCP_UPDATE_CLIENT_MESSAGE_TYPE_URL.to_string(),
h.encode_vec().unwrap(),
Expand Down Expand Up @@ -100,6 +110,37 @@ impl From<RegisterEnclaveKeyMessage> for RawRegisterEnclaveKeyMessage {
}
}

#[derive(Debug, Clone, PartialEq)]
pub struct ZKDCAPRegisterEnclaveKeyMessage {
pub commit: DCAPVerifierCommit,
pub proof: Vec<u8>,
pub operator_signature: Option<Vec<u8>>,
}

impl Protobuf<RawZKDCAPRegisterEnclaveKeyMessage> for ZKDCAPRegisterEnclaveKeyMessage {}

impl TryFrom<RawZKDCAPRegisterEnclaveKeyMessage> for ZKDCAPRegisterEnclaveKeyMessage {
type Error = Error;
fn try_from(value: RawZKDCAPRegisterEnclaveKeyMessage) -> Result<Self, Self::Error> {
Ok(ZKDCAPRegisterEnclaveKeyMessage {
commit: DCAPVerifierCommit::from_bytes(&value.commit),
proof: value.proof,
operator_signature: (!value.operator_signature.is_empty())
.then_some(value.operator_signature),
})
}
}

impl From<ZKDCAPRegisterEnclaveKeyMessage> for RawZKDCAPRegisterEnclaveKeyMessage {
fn from(value: ZKDCAPRegisterEnclaveKeyMessage) -> Self {
RawZKDCAPRegisterEnclaveKeyMessage {
commit: value.commit.to_bytes(),
proof: value.proof,
operator_signature: value.operator_signature.unwrap_or_default(),
}
}
}

#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct UpdateClientMessage {
pub signatures: Vec<Vec<u8>>,
Expand Down
2 changes: 1 addition & 1 deletion modules/remote-attestation/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ reqwest = { version = "0.12.9", default-features = false, features = [
] }
urlencoding = { version = "2" }

dcap-rs = { git = "https://github.com/bluele/dcap-rs", rev = "71fe1e02f151a28bf5661b01dba5096730564840" }
dcap-rs = { git = "https://github.com/bluele/dcap-rs", rev = "c3098b6a3c9faa4a884c87db65d0f586000bcf16" }

lcp-types = { path = "../types" }
crypto = { path = "../crypto", default-features = false }
Expand Down
6 changes: 6 additions & 0 deletions proto/definitions/ibc/lightclients/lcp/v1/lcp.proto
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ message RegisterEnclaveKeyMessage {
bytes operator_signature = 4;
}

message ZKDCAPRegisterEnclaveKeyMessage {
bytes commit = 1;
bytes proof = 2;
bytes operator_signature = 3;
}

message UpdateOperatorsMessage {
uint64 nonce = 1;
repeated bytes new_operators = 2;
Expand Down
Binary file modified proto/src/descriptor.bin
Binary file not shown.
10 changes: 10 additions & 0 deletions proto/src/prost/ibc.lightclients.lcp.v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ pub struct RegisterEnclaveKeyMessage {
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ZkdcapRegisterEnclaveKeyMessage {
#[prost(bytes = "vec", tag = "1")]
pub commit: ::prost::alloc::vec::Vec<u8>,
#[prost(bytes = "vec", tag = "2")]
pub proof: ::prost::alloc::vec::Vec<u8>,
#[prost(bytes = "vec", tag = "3")]
pub operator_signature: ::prost::alloc::vec::Vec<u8>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct UpdateOperatorsMessage {
#[prost(uint64, tag = "1")]
pub nonce: u64,
Expand Down

0 comments on commit e8e9329

Please sign in to comment.