Skip to content

Commit

Permalink
enclaves: light client check (#69)
Browse files Browse the repository at this point in the history
Co-authored-by: dave <[email protected]>
  • Loading branch information
hu55a1n1 and dave authored Jul 24, 2024
1 parent e1b13a0 commit 2a4e7f5
Show file tree
Hide file tree
Showing 9 changed files with 179 additions and 90 deletions.
31 changes: 31 additions & 0 deletions Cargo.lock

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

7 changes: 6 additions & 1 deletion apps/mtcs/enclave/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,17 @@ tendermint.workspace = true
tendermint-light-client.workspace = true

# quartz
cw-proof.workspace = true
cw-tee-mtcs.workspace = true
cycles-sync.workspace = true
mtcs.workspace = true
quartz-cw.workspace = true
quartz-proto.workspace = true
quartz-enclave.workspace = true
quartz-proto.workspace = true

[dev-dependencies]
cw-multi-test = "2.0.0"
serde_json = "1.0.113"

[build-dependencies]
tonic-build.workspace = true
5 changes: 2 additions & 3 deletions apps/mtcs/enclave/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
clippy::checked_conversions,
clippy::panic,
clippy::panic_in_result_fn,
missing_docs,
trivial_casts,
trivial_numeric_casts,
rust_2018_idioms,
Expand Down Expand Up @@ -65,11 +64,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {

Server::builder()
.add_service(CoreServer::new(CoreService::new(
config,
config.clone(),
sk.clone(),
attestor.clone(),
)))
.add_service(MtcsServer::new(MtcsService::new(sk, attestor)))
.add_service(MtcsServer::new(MtcsService::new(config, sk, attestor)))
.serve(args.rpc_addr)
.await?;

Expand Down
42 changes: 20 additions & 22 deletions apps/mtcs/enclave/src/mtcs_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ use mtcs::{
algo::mcmf::primal_dual::PrimalDual, impls::complex_id::ComplexIdMtcs,
obligation::SimpleObligation, prelude::DefaultMtcs, setoff::SimpleSetoff, Mtcs,
};
use quartz_cw::msg::execute::attested::RawAttested;
use quartz_enclave::attestor::Attestor;
use quartz_cw::{msg::execute::attested::RawAttested, state::Config};
use quartz_enclave::{attestor::Attestor, server::ProofOfPublication};
use serde::{Deserialize, Serialize};
use tonic::{Request, Response, Result as TonicResult, Status};

Expand All @@ -28,6 +28,7 @@ pub type RawCipherText = HexBinary;

#[derive(Clone, Debug)]
pub struct MtcsService<A> {
config: Config,
sk: Arc<Mutex<Option<SigningKey>>>,
attestor: A,
}
Expand All @@ -42,8 +43,12 @@ impl<A> MtcsService<A>
where
A: Attestor,
{
pub fn new(sk: Arc<Mutex<Option<SigningKey>>>, attestor: A) -> Self {
Self { sk, attestor }
pub fn new(config: Config, sk: Arc<Mutex<Option<SigningKey>>>, attestor: A) -> Self {
Self {
config,
sk,
attestor,
}
}
}

Expand All @@ -56,28 +61,21 @@ where
&self,
request: Request<RunClearingRequest>,
) -> TonicResult<Response<RunClearingResponse>> {
// Pass in JSON of Requests vector and the STATE

// Serialize into Requests enum
// Loop through, decrypt the ciphertexts

// Read the state blob from chain

// Decrypt and deserialize

// Loop through requests and apply onto state

// Encrypt state

// Create withdraw requests

// Send to chain

let message: RunClearingMessage = {
let message: ProofOfPublication<RunClearingMessage> = {
let message = request.into_inner().message;
serde_json::from_str(&message).map_err(|e| Status::invalid_argument(e.to_string()))?
};

let (proof_value, message) = message
.verify(self.config.light_client_opts())
.map_err(Status::failed_precondition)?;

let proof_value_matches_msg =
serde_json::to_string(&message.intents).is_ok_and(|s| s.as_bytes() == proof_value);
if !proof_value_matches_msg {
return Err(Status::failed_precondition("proof verification"));
}

let digests_ciphertexts = message.intents;
let (digests, ciphertexts): (Vec<_>, Vec<_>) = digests_ciphertexts.into_iter().unzip();

Expand Down
3 changes: 1 addition & 2 deletions apps/transfers/enclave/bin/encrypt.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::collections::BTreeMap;

use anyhow;
use cosmwasm_std::{Addr, HexBinary, Uint128};
use ecies::encrypt;
use k256::ecdsa::VerifyingKey;
Expand Down Expand Up @@ -42,7 +41,7 @@ fn main() {
let msg = ClearTextTransferRequestMsg {
sender: Addr::unchecked("alice"),
receiver: Addr::unchecked("bob"),
amount: Uint128::from(100 as u32),
amount: Uint128::from(100_u32),
};

let decoded: Vec<u8> =
Expand Down
6 changes: 4 additions & 2 deletions apps/transfers/enclave/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {

Server::builder()
.add_service(CoreServer::new(CoreService::new(
config,
config.clone(),
sk.clone(),
attestor.clone(),
)))
.add_service(TransfersServer::new(TransfersService::new(sk, attestor)))
.add_service(TransfersServer::new(TransfersService::new(
config, sk, attestor,
)))
.serve(args.rpc_addr)
.await?;

Expand Down
27 changes: 20 additions & 7 deletions apps/transfers/enclave/src/transfers_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ use ecies::{decrypt, encrypt};
use k256::ecdsa::{SigningKey, VerifyingKey};
use quartz_cw::{
msg::execute::attested::{HasUserData, RawAttested},
state::UserData,
state::{Config, UserData},
};
use quartz_enclave::attestor::Attestor;
use quartz_enclave::{attestor::Attestor, server::ProofOfPublication};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use tonic::{Request, Response, Result as TonicResult, Status};
Expand All @@ -27,6 +27,7 @@ pub type RawCipherText = HexBinary;

#[derive(Clone, Debug)]
pub struct TransfersService<A> {
config: Config,
sk: Arc<Mutex<Option<SigningKey>>>,
attestor: A,
}
Expand Down Expand Up @@ -91,8 +92,12 @@ impl<A> TransfersService<A>
where
A: Attestor,
{
pub fn new(sk: Arc<Mutex<Option<SigningKey>>>, attestor: A) -> Self {
Self { sk, attestor }
pub fn new(config: Config, sk: Arc<Mutex<Option<SigningKey>>>, attestor: A) -> Self {
Self {
config,
sk,
attestor,
}
}
}

Expand All @@ -102,14 +107,22 @@ where
A: Attestor + Send + Sync + 'static,
{
async fn run(&self, request: Request<UpdateRequest>) -> TonicResult<Response<UpdateResponse>> {
// Request contains a serialized json string

// Serialize request into struct containing State and the Requests vec
let message: UpdateRequestMessage = {
let message: ProofOfPublication<UpdateRequestMessage> = {
let message = request.into_inner().message;
serde_json::from_str(&message).map_err(|e| Status::invalid_argument(e.to_string()))?
};

let (proof_value, message) = message
.verify(self.config.light_client_opts())
.map_err(Status::failed_precondition)?;

let proof_value_matches_msg =
serde_json::to_string(&message.requests).is_ok_and(|s| s.as_bytes() == proof_value);
if !proof_value_matches_msg {
return Err(Status::failed_precondition("proof verification"));
}

// Decrypt and deserialize the state
let mut state = {
if message.state.len() == 1 && message.state[0] == 0 {
Expand Down
42 changes: 40 additions & 2 deletions apps/transfers/scripts/listen.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,57 @@ REPORT_SIG_FILE="/tmp/${USER}_datareportsig"
if echo "$CLEAN_MSG" | grep -q 'wasm-transfer'; then
echo "---------------------------------------------------------"
echo "... received wasm-transfer event!"

current_height=$($CMD status | jq -r .SyncInfo.latest_block_height)
next_height=$((current_height + 1))

while [ "$($CMD status 2>&1 | jq -r .SyncInfo.latest_block_height)" -lt "$next_height" ]; do
echo "waiting for next block"
sleep 1
done

echo "... fetching requests"
REQUESTS=$($CMD query wasm contract-state raw $CONTRACT $(printf '%s' "requests" | \
hexdump -ve '/1 "%02X"') -o json | jq -r .data | base64 -d)
STATE=$($CMD query wasm contract-state raw $CONTRACT $(printf '%s' "state" | \
hexdump -ve '/1 "%02X"') -o json | jq -r .data | base64 -d)

cd "$ROOT/cycles-quartz/apps/transfers"
export TRUSTED_HASH=$(cat trusted.hash)
export TRUSTED_HEIGHT=$(cat trusted.height)

cd $ROOT/cycles-quartz/utils/tm-prover
export PROOF_FILE="light-client-proof.json"
if [ -f "$PROOF_FILE" ]; then
rm "$PROOF_FILE"
echo "removed old $PROOF_FILE"
fi

echo "trusted hash $TRUSTED_HASH"
echo "trusted hash $TRUSTED_HEIGHT"
echo "contract $CONTRACT"

# run prover to get light client proof
cargo run -- --chain-id testing \
--primary "http://$NODE_URL" \
--witnesses "http://$NODE_URL" \
--trusted-height $TRUSTED_HEIGHT \
--trusted-hash $TRUSTED_HASH \
--contract-address $CONTRACT \
--storage-key "requests" \
--trace-file $PROOF_FILE

export POP=$(cat $PROOF_FILE)

export ENCLAVE_REQUEST=$(jq -nc --argjson requests "$REQUESTS" --argjson state $STATE '$ARGS.named')
export REQUEST_MSG=$(jq -nc --arg message "$ENCLAVE_REQUEST" '$ARGS.named')
export REQUEST_MSG=$(jq --argjson msg "$ENCLAVE_REQUEST" '. + {msg: $msg}' <<< "$POP")
export PROTO_MSG=$(jq -nc --arg message "$REQUEST_MSG" '$ARGS.named')

cd $ROOT/cycles-quartz/apps/transfers/enclave

echo "... executing transfer"
export ATTESTED_MSG=$(grpcurl -plaintext -import-path ./proto/ -proto transfers.proto \
-d "$REQUEST_MSG" "127.0.0.1:$QUARTZ_PORT" transfers.Settlement/Run | \
-d "$PROTO_MSG" "127.0.0.1:$QUARTZ_PORT" transfers.Settlement/Run | \
jq .message | jq -R 'fromjson | fromjson' | jq -c)
QUOTE=$(echo "$ATTESTED_MSG" | jq -c '.attestation')
MSG=$(echo "$ATTESTED_MSG" | jq -c '.msg')
Expand Down
Loading

0 comments on commit 2a4e7f5

Please sign in to comment.