Mock attestation (#82)

Co-authored-by: Ethan Buchman <ethan@coinculture.info>
This commit is contained in:
Shoaib Ahmed 2024-07-19 01:34:31 +02:00 committed by GitHub
parent fe06f244ad
commit 4b3630adf3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 228 additions and 4299 deletions

1
Cargo.lock generated
View file

@ -2379,6 +2379,7 @@ dependencies = [
"quartz-proto",
"serde",
"serde_json",
"sha2 0.10.8",
"tendermint 0.36.0",
"tendermint-light-client",
"thiserror",

View file

@ -19,6 +19,9 @@ panic = 'abort'
incremental = false
overflow-checks = true
[features]
mock-sgx = ["quartz-cw/mock-sgx"]
[dependencies]
# external
hex = { version = "0.4.3", default-features = false }

View file

@ -3,26 +3,26 @@ use std::collections::BTreeMap;
use cosmwasm_schema::{cw_serde, QueryResponses};
use cosmwasm_std::{HexBinary, Uint64};
use quartz_cw::{
msg::execute::attested::{RawAttested, RawAttestedMsgSansHandler, RawEpidAttestation},
msg::execute::attested::{RawAttested, RawAttestedMsgSansHandler, RawDefaultAttestation},
prelude::*,
};
use crate::state::{RawHash, SettleOff};
type AttestedMsg<M> = RawAttested<RawAttestedMsgSansHandler<M>, RawEpidAttestation>;
type AttestedMsg<M, RA> = RawAttested<RawAttestedMsgSansHandler<M>, RA>;
#[cw_serde]
pub struct InstantiateMsg(pub QuartzInstantiateMsg);
pub struct InstantiateMsg<RA = RawDefaultAttestation>(pub QuartzInstantiateMsg<RA>);
#[cw_serde]
#[allow(clippy::large_enum_variant)]
pub enum ExecuteMsg {
pub enum ExecuteMsg<RA = RawDefaultAttestation> {
Quartz(QuartzExecuteMsg),
FaucetMint(execute::FaucetMintMsg),
Transfer(execute::Cw20Transfer),
SubmitObligation(execute::SubmitObligationMsg),
SubmitObligations(execute::SubmitObligationsMsg),
SubmitSetoffs(AttestedMsg<execute::SubmitSetoffsMsg>),
SubmitSetoffs(AttestedMsg<execute::SubmitSetoffsMsg, RA>),
InitClearing,
SetLiquiditySources(execute::SetLiquiditySourcesMsg),
}

View file

@ -4,6 +4,9 @@ version = "0.1.0"
edition = "2021"
authors = ["Informal Systems <hello@informal.systems>"]
[features]
mock-sgx = ["quartz-cw/mock-sgx", "quartz-enclave/mock-sgx"]
[dependencies]
# external
clap.workspace = true

View file

@ -28,7 +28,7 @@ use mtcs_server::MtcsService;
use proto::clearing_server::ClearingServer as MtcsServer;
use quartz_cw::state::{Config, LightClientOpts};
use quartz_enclave::{
attestor::{Attestor, EpidAttestor},
attestor::{Attestor, DefaultAttestor},
server::CoreService,
};
use quartz_proto::quartz::core_server::CoreServer;
@ -53,8 +53,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
args.max_block_lag,
)?;
let attestor = DefaultAttestor::default();
let config = Config::new(
EpidAttestor.mr_enclave()?,
attestor.mr_enclave()?,
Duration::from_secs(30 * 24 * 60),
light_client_opts,
);
@ -65,9 +67,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.add_service(CoreServer::new(CoreService::new(
config,
sk.clone(),
EpidAttestor,
attestor.clone(),
)))
.add_service(MtcsServer::new(MtcsService::new(sk.clone(), EpidAttestor)))
.add_service(MtcsServer::new(MtcsService::new(sk, attestor)))
.serve(args.rpc_addr)
.await?;

View file

@ -20,8 +20,8 @@ You may want to exit and start a new terminal session to get the rust toolchain
Now downgrade rust to v1.76.0:
```
rustup install v1.76.0
rustup default v1.76.0
rustup install 1.76.0
rustup default 1.76.0
```
Check the version with `cargo version`.
@ -61,7 +61,7 @@ git checkout v0.44.0
go install ./cmd/wasmd
```
Check that both work by running `grpccurl` and `wasmd`.
Check that both work by running `grpcurl` and `wasmd`.
Finally, you neeed `websocat`:
@ -114,6 +114,19 @@ First set the `NODE_URL` variable to the address of the blockchain node. If it's
The `scripts` dir contains some bash scripts to help run the app.
These scripts should be replaced by a new `quartz` tool. See [issue](https://github.com/informalsystems/cycles-quartz/issues/61).
Note: to build/run on a non-SGX machine you must set the `MOCK_SGX` env var for all bash scripts below
```
# 1st Terminal
$ export MOCK_SGX=1
$ bash scripts/build.sh
$ bash scripts/start.sh
# 2nd Terminal
$ export MOCK_SGX=1
$ bash scripts/deploy.sh
$ ...
```
### Build the Binaries
Build the enclave binary and the smart contract binary:

View file

@ -23,6 +23,9 @@ panic = 'abort'
incremental = false
overflow-checks = true
[features]
mock-sgx = ["quartz-cw/mock-sgx"]
[dependencies]
# external
sha2 = "0.10.8"

View file

@ -1,5 +1,5 @@
use cosmwasm_schema::write_api;
use transfers_contracts::msg::{ExecuteMsg, InstantiateMsg};
use transfers_contract::msg::{ExecuteMsg, InstantiateMsg};
fn main() {
write_api! {

View file

@ -1 +1,8 @@
RUSTFLAGS='-C link-arg=-s' cargo wasm
FEATURES=
if [ -n "$MOCK_SGX" ]; then
echo "MOCK_SGX is set. Adding mock-sgx feature."
FEATURES="--features=mock-sgx"
fi
RUSTFLAGS='-C link-arg=-s' cargo wasm $FEATURES

View file

@ -60,7 +60,7 @@ TX_HASH=$(echo $RES | jq -r '.["txhash"]')
echo ""
while ! $CMD query tx $TX_HASH &> /dev/null; do
echo "... 🕐 waiting for contract to be queryable"
echo "... 🕐 waiting for contract to be queryable from tx hash $TX_HASH"
sleep 1
done

View file

@ -1,19 +1,19 @@
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Addr, HexBinary, Uint128};
use quartz_cw::{
msg::execute::attested::{RawAttested, RawEpidAttestation},
msg::execute::attested::{RawAttested, RawDefaultAttestation},
prelude::*,
};
#[cw_serde]
pub struct InstantiateMsg {
pub quartz: QuartzInstantiateMsg,
pub struct InstantiateMsg<RA = RawDefaultAttestation> {
pub quartz: QuartzInstantiateMsg<RA>,
pub denom: String,
}
#[cw_serde]
#[allow(clippy::large_enum_variant)]
pub enum ExecuteMsg {
pub enum ExecuteMsg<RA = RawDefaultAttestation> {
// quartz initialization
Quartz(QuartzExecuteMsg),
@ -28,7 +28,7 @@ pub enum ExecuteMsg {
ClearTextTransferRequest(execute::ClearTextTransferRequestMsg),
// enclave msg
Update(RawAttested<execute::RawUpdateMsg, RawEpidAttestation>),
Update(RawAttested<execute::RawUpdateMsg, RA>),
}
pub mod execute {

File diff suppressed because it is too large Load diff

View file

@ -3,12 +3,15 @@ name = "quartz-app-transfers-enclave"
version = "0.1.0"
edition = "2021"
authors = ["Informal Systems <hello@informal.systems>"]
autobins = false
default-run = "quartz-app-transfers-enclave"
[[bin]]
name = "encrypt"
path = "bin/encrypt.rs"
[features]
mock-sgx = ["quartz-cw/mock-sgx", "quartz-enclave/mock-sgx"]
[dependencies]
# external
anyhow.workspace = true
@ -20,6 +23,7 @@ k256.workspace = true
prost.workspace = true
serde.workspace = true
serde_json.workspace = true
sha2.workspace = true
thiserror.workspace = true
tokio.workspace = true
tonic.workspace = true

View file

@ -1,12 +1,9 @@
use std::collections::{BTreeMap, HashMap};
use std::collections::BTreeMap;
use anyhow;
use cosmwasm_std::{Addr, HexBinary, Uint128};
use ecies::{decrypt, encrypt};
use k256::{
ecdsa::{SigningKey, VerifyingKey},
pkcs8::DecodePublicKey,
};
use ecies::encrypt;
use k256::ecdsa::VerifyingKey;
use serde::{Deserialize, Serialize};
use transfers_contract::msg::execute::ClearTextTransferRequestMsg;

View file

@ -1,7 +1,7 @@
# Quartz manifest file
loader.entrypoint = "file:{{ gramine.libos }}"
libos.entrypoint = "{{ quartz_dir }}/target/release/enclave"
libos.entrypoint = "{{ quartz_dir }}/target/release/quartz-app-transfers-enclave"
loader.log_level = "{{ log_level }}"
@ -20,7 +20,7 @@ loader.env.RA_TLS_EPID_API_KEY = { passthrough = true }
loader.env.MYAPP_DATA = { passthrough = true }
loader.env.QUARTZ_PORT = { passthrough = true }
loader.argv = ["enclave",
loader.argv = ["quartz-app-transfers-enclave",
"--chain-id", "testing",
"--trusted-height", "{{ trusted_height }}",
"--trusted-hash", "{{ trusted_hash }}"]
@ -43,7 +43,7 @@ sgx.ra_client_linkable = {{ 'true' if ra_client_linkable == '1' else 'false' }}
sgx.trusted_files = [
"file:{{ gramine.libos }}",
"file:{{ quartz_dir }}/target/release/enclave",
"file:{{ quartz_dir }}/target/release/quartz-app-transfers-enclave",
"file:{{ gramine.runtimedir() }}/",
"file:{{ arch_libdir }}/",
"file:/usr/{{ arch_libdir }}/",

View file

@ -51,8 +51,9 @@ pub struct Cli {
pub max_block_lag: u64,
}
fn default_rpc_addr() -> SocketAddr {
let port = env::var("QUARTZ_PORT").unwrap_or_else(|_| "11090".to_string());
format!("127.0.0.1:{}", port).parse().expect("Invalid socket address")
format!("127.0.0.1:{}", port)
.parse()
.expect("Invalid socket address")
}

View file

@ -4,7 +4,6 @@
clippy::checked_conversions,
clippy::panic,
clippy::panic_in_result_fn,
missing_docs,
trivial_casts,
trivial_numeric_casts,
rust_2018_idioms,
@ -28,7 +27,7 @@ use cli::Cli;
use proto::settlement_server::SettlementServer as TransfersServer;
use quartz_cw::state::{Config, LightClientOpts};
use quartz_enclave::{
attestor::{Attestor, EpidAttestor},
attestor::{Attestor, DefaultAttestor},
server::CoreService,
};
use quartz_proto::quartz::core_server::CoreServer;
@ -54,8 +53,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
args.max_block_lag,
)?;
let attestor = DefaultAttestor::default();
let config = Config::new(
EpidAttestor.mr_enclave()?,
attestor.mr_enclave()?,
Duration::from_secs(30 * 24 * 60),
light_client_opts,
);
@ -66,12 +67,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.add_service(CoreServer::new(CoreService::new(
config,
sk.clone(),
EpidAttestor,
)))
.add_service(TransfersServer::new(TransfersService::<EpidAttestor>::new(
sk.clone(),
EpidAttestor,
attestor.clone(),
)))
.add_service(TransfersServer::new(TransfersService::new(sk, attestor)))
.serve(args.rpc_addr)
.await?;

View file

@ -1,4 +1,4 @@
use std::collections::{BTreeMap, HashMap};
use std::collections::BTreeMap;
use anyhow;
use cosmwasm_std::{Addr, HexBinary, Uint128};

View file

@ -4,9 +4,6 @@ use std::{
};
use cosmwasm_std::{Addr, HexBinary, Uint128};
pub type RawCipherText = HexBinary;
use ecies::{decrypt, encrypt};
use k256::ecdsa::{SigningKey, VerifyingKey};
use quartz_cw::{
@ -17,13 +14,15 @@ use quartz_enclave::attestor::Attestor;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use tonic::{Request, Response, Result as TonicResult, Status};
use transfers_contracts::msg::execute::{ClearTextTransferRequestMsg, Request as TransfersRequest};
use transfers_contract::msg::execute::{ClearTextTransferRequestMsg, Request as TransfersRequest};
use crate::{
proto::{settlement_server::Settlement, RunTransfersRequest, RunTransfersResponse},
state::{RawState, State},
};
pub type RawCipherText = HexBinary;
#[derive(Clone, Debug)]
pub struct TransfersService<A> {
sk: Arc<Mutex<Option<SigningKey>>>,
@ -178,10 +177,11 @@ where
};
// Attest to message
let attestation = self
let attestation: HexBinary = self
.attestor
.quote(msg.clone())
.map_err(|e| Status::internal(e.to_string()))?;
.map_err(|e| Status::internal(e.to_string()))?
.into();
let attested_msg = RawAttested { msg, attestation };
let message =

View file

@ -3,16 +3,22 @@
set -eo pipefail
ROOT=${ROOT:-$HOME}
FEATURES=
if [ -n "$MOCK_SGX" ]; then
echo "MOCK_SGX is set. Adding mock-sgx feature."
FEATURES="--features=mock-sgx"
fi
echo "--------------------------------------------------------"
echo "building enclave binary"
cd $ROOT/cycles-quartz/apps/transfers/enclave
CARGO_TARGET_DIR=./target cargo build --release
CARGO_TARGET_DIR=./target cargo build --release $FEATURES
echo "--------------------------------------------------------"
echo "building cosmwasm contract binary"
cd $ROOT/cycles-quartz/apps/transfers/contracts
bash build.sh
bash build.sh $FEATURES

View file

@ -9,12 +9,13 @@ echo "--------------------------------------------------------"
echo "instantiate"
cd $ROOT/cycles-quartz/relayer/
export INSTANTIATE_MSG=$(./scripts/relay.sh Instantiate | jq '{quartz: .} + {denom: "ucosm"}' )
echo $INSTANTIATE_MSG
echo "--------------------------------------------------------"
echo "deploy contract"
cd $ROOT/cycles-quartz/apps/transfers/contracts/
bash deploy-contract.sh target/wasm32-unknown-unknown/release/transfers_contracts.wasm |& tee output
bash deploy-contract.sh target/wasm32-unknown-unknown/release/transfers_contract.wasm 2>&1 | tee output
export CONTRACT=$(cat output | grep Address | awk '{print $NF}' | sed 's/\x1b\[[0-9;]*m//g')
echo $CONTRACT

View file

@ -36,6 +36,7 @@ cd $ROOT/cycles-quartz/relayer
# execute SessionCreate on enclave
export EXECUTE_CREATE=$(./scripts/relay.sh SessionCreate)
echo $EXECUTE_CREATE
# submit SessionCreate to contract
RES=$($CMD tx wasm execute "$CONTRACT" "$EXECUTE_CREATE" --from admin --chain-id testing -y --output json)
@ -43,14 +44,14 @@ TX_HASH=$(echo $RES | jq -r '.["txhash"]')
# wait for tx to commit
while ! $CMD query tx $TX_HASH &> /dev/null; do
echo "... 🕐 waiting for tx"
echo "... 🕐 waiting for tx $TX_HASH"
sleep 1
done
# need to wait another block for light client proof
BLOCK_HEIGHT=$($CMD query block | jq .block.header.height)
echo "at heigh $BLOCK_HEIGHT. need to wait for a block"
echo "at height $BLOCK_HEIGHT. need to wait for a block"
while [[ $BLOCK_HEIGHT == $($CMD query block | jq .block.header.height) ]]; do
echo "... 🕐 waiting for another block"
sleep 1
@ -58,7 +59,7 @@ done
# need to wait another block for light client proof
BLOCK_HEIGHT=$($CMD query block | jq .block.header.height)
echo "at heigh $BLOCK_HEIGHT. need to wait for a block"
echo "at height $BLOCK_HEIGHT. need to wait for a block"
while [[ $BLOCK_HEIGHT == $($CMD query block | jq .block.header.height) ]]; do
echo "... 🕐 waiting for another block"
sleep 1
@ -78,12 +79,13 @@ fi
# TODO: pass this in?
echo "trusted hash $TRUSTED_HASH"
echo "trusted hash $TRUSTED_HEIGHT"
echo "contract $CONTRACT"
# run prover to get light client proof
# TODO: assume this binary is pre-built?
# TODO: pass in addresses and chain id
cargo run -vvv -- --chain-id testing \
cargo run -- --chain-id testing \
--primary "http://$NODE_URL" \
--witnesses "http://$NODE_URL" \
--trusted-height $TRUSTED_HEIGHT \
@ -104,7 +106,7 @@ TX_HASH=$(echo $RES | jq -r '.["txhash"]')
# wait for tx to commit
while ! $CMD query tx $TX_HASH &> /dev/null; do
echo "... 🕐 waiting for tx"
echo "... 🕐 waiting for tx $TX_HASH"
sleep 1
done

View file

@ -25,6 +25,14 @@ cd ""$DIR_QUARTZ_APP""
echo "$TRUSTED_HASH" > trusted.hash
echo "$TRUSTED_HEIGHT" > trusted.height
if [ -n "$MOCK_SGX" ]; then
echo "MOCK_SGX is set. Running enclave without gramine..."
cd $DIR_QUARTZ_ENCLAVE
./target/release/quartz-app-transfers-enclave --chain-id "testing" --trusted-height "$TRUSTED_HEIGHT" --trusted-hash "$TRUSTED_HASH"
exit
fi
echo "--------------------------------------------------------"
echo "configure gramine"
cd "$DIR_QUARTZ_ENCLAVE"

View file

@ -9,8 +9,8 @@ repository.workspace = true
keywords = ["blockchain", "cosmos", "tendermint", "cycles", "quartz"]
readme = "README.md"
[lib]
path = "src/lib.rs"
[features]
mock-sgx = ["quartz-cw/mock-sgx"]
[dependencies]
# external

View file

@ -8,6 +8,12 @@ use quartz_cw::{
state::{MrEnclave, UserData},
};
#[cfg(not(feature = "mock-sgx"))]
pub type DefaultAttestor = EpidAttestor;
#[cfg(feature = "mock-sgx")]
pub type DefaultAttestor = MockAttestor;
pub trait Attestor {
type Error: ToString;
@ -16,7 +22,7 @@ pub trait Attestor {
fn mr_enclave(&self) -> Result<MrEnclave, Self::Error>;
}
#[derive(Clone, PartialEq, Debug)]
#[derive(Clone, PartialEq, Debug, Default)]
pub struct EpidAttestor;
impl Attestor for EpidAttestor {
@ -38,18 +44,19 @@ impl Attestor for EpidAttestor {
}
}
#[derive(Clone, PartialEq, Debug)]
#[derive(Clone, PartialEq, Debug, Default)]
pub struct MockAttestor;
impl Attestor for MockAttestor {
type Error = String;
fn quote(&self, _user_data: impl HasUserData) -> Result<Vec<u8>, Self::Error> {
Ok(vec![])
fn quote(&self, user_data: impl HasUserData) -> Result<Vec<u8>, Self::Error> {
let user_data = user_data.user_data();
Ok(user_data.to_vec())
}
fn mr_enclave(&self) -> Result<MrEnclave, Self::Error> {
Ok([0u8; 32])
Ok(Default::default())
}
}

View file

@ -4,7 +4,6 @@
clippy::checked_conversions,
clippy::panic,
clippy::panic_in_result_fn,
missing_docs,
trivial_casts,
trivial_numeric_casts,
rust_2018_idioms,

View file

@ -9,6 +9,9 @@ repository.workspace = true
keywords = ["blockchain", "cosmos", "cosmwasm", "cycles", "quartz"]
readme = "README.md"
[features]
mock-sgx = []
[dependencies]
# external
k256.workspace = true

View file

@ -7,7 +7,7 @@ use cosmwasm_std::StdError;
use crate::msg::{
execute::{
attested::{Attested, EpidAttestation, RawAttested, RawEpidAttestation},
attested::{Attested, DefaultAttestation, RawAttested, RawDefaultAttestation},
session_create::{RawSessionCreate, SessionCreate},
session_set_pub_key::{RawSessionSetPubKey, SessionSetPubKey},
},
@ -15,13 +15,13 @@ use crate::msg::{
};
#[derive(Clone, Debug, PartialEq)]
pub enum Execute<Attestation = EpidAttestation> {
pub enum Execute<Attestation = DefaultAttestation> {
SessionCreate(Attested<SessionCreate, Attestation>),
SessionSetPubKey(Attested<SessionSetPubKey, Attestation>),
}
#[cw_serde]
pub enum RawExecute<RawAttestation = RawEpidAttestation> {
pub enum RawExecute<RawAttestation = RawDefaultAttestation> {
#[serde(rename = "session_create")]
RawSessionCreate(RawAttested<RawSessionCreate, RawAttestation>),
#[serde(rename = "session_set_pub_key")]

View file

@ -1,7 +1,19 @@
use std::{convert::Into, default::Default};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::StdError;
use cosmwasm_std::{HexBinary, StdError};
use quartz_tee_ra::IASReport;
#[cfg(not(feature = "mock-sgx"))]
pub type DefaultAttestation = EpidAttestation;
#[cfg(not(feature = "mock-sgx"))]
pub type RawDefaultAttestation = RawEpidAttestation;
#[cfg(feature = "mock-sgx")]
pub type DefaultAttestation = MockAttestation;
#[cfg(feature = "mock-sgx")]
pub type RawDefaultAttestation = RawMockAttestation;
use crate::{
msg::HasDomainType,
state::{MrEnclave, UserData},
@ -137,22 +149,28 @@ impl Attestation for EpidAttestation {
}
#[derive(Clone, Debug, PartialEq)]
pub struct MockAttestation;
pub struct MockAttestation(pub UserData);
impl Default for MockAttestation {
fn default() -> Self {
Self([0u8; 64])
}
}
#[cw_serde]
pub struct RawMockAttestation;
pub struct RawMockAttestation(pub HexBinary);
impl TryFrom<RawMockAttestation> for MockAttestation {
type Error = StdError;
fn try_from(_value: RawMockAttestation) -> Result<Self, Self::Error> {
Ok(Self)
fn try_from(value: RawMockAttestation) -> Result<Self, Self::Error> {
Ok(Self(value.0.to_array()?))
}
}
impl From<MockAttestation> for RawMockAttestation {
fn from(_value: MockAttestation) -> Self {
Self
fn from(value: MockAttestation) -> Self {
Self(value.0.into())
}
}
@ -162,13 +180,13 @@ impl HasDomainType for RawMockAttestation {
impl HasUserData for MockAttestation {
fn user_data(&self) -> UserData {
unimplemented!("MockAttestation handler is a noop")
self.0
}
}
impl Attestation for MockAttestation {
fn mr_enclave(&self) -> MrEnclave {
unimplemented!("MockAttestation handler is a noop")
Default::default()
}
}

View file

@ -5,7 +5,7 @@ use sha2::{Digest, Sha256};
use crate::{
msg::{
execute::attested::{
Attested, EpidAttestation, HasUserData, RawAttested, RawEpidAttestation,
Attested, DefaultAttestation, HasUserData, RawAttested, RawDefaultAttestation,
},
HasDomainType,
},
@ -13,10 +13,10 @@ use crate::{
};
#[derive(Clone, Debug, PartialEq)]
pub struct Instantiate<A = EpidAttestation>(pub Attested<CoreInstantiate, A>);
pub struct Instantiate<A = DefaultAttestation>(pub Attested<CoreInstantiate, A>);
#[cw_serde]
pub struct RawInstantiate<RA = RawEpidAttestation>(RawAttested<RawCoreInstantiate, RA>);
pub struct RawInstantiate<RA = RawDefaultAttestation>(RawAttested<RawCoreInstantiate, RA>);
impl<RA> TryFrom<RawInstantiate<RA>> for Instantiate<RA::DomainType>
where

View file

@ -9,6 +9,9 @@ repository.workspace = true
keywords = ["blockchain", "cosmos", "tendermint", "cycles", "quartz"]
readme = "README.md"
[features]
mock-sgx = ["quartz-cw/mock-sgx"]
[dependencies]
# external
clap.workspace = true

View file

@ -3,9 +3,9 @@
set -eo pipefail
usage() {
echo "Usage: $0 <REQUEST> <REQUEST_MSG>"
echo " <REQUEST>: Instantiate | SessionCreate | SessionSetPubKey"
exit 1
echo "Usage: $0 <REQUEST> <REQUEST_MSG>"
echo " <REQUEST>: Instantiate | SessionCreate | SessionSetPubKey"
exit 1
}
ROOT=${ROOT:-$HOME}
@ -23,9 +23,6 @@ REQUEST_MSG=${2:-"{}"}
# Use the QUARTZ_PORT environment variable if set, otherwise default to 11090
QUARTZ_PORT="${QUARTZ_PORT:-11090}"
# clear tmp files from previous runs
rm -f "$QUOTE_FILE" "$REPORT_FILE" "$REPORT_SIG_FILE"
# query the gRPC quartz enclave service
ATTESTED_MSG=$(grpcurl -plaintext -import-path "$DIR_PROTO" -proto quartz.proto -d "$REQUEST_MSG" "127.0.0.1:$QUARTZ_PORT" quartz.Core/"$REQUEST" | jq -c '.message | fromjson')
@ -33,6 +30,29 @@ ATTESTED_MSG=$(grpcurl -plaintext -import-path "$DIR_PROTO" -proto quartz.proto
QUOTE=$(echo "$ATTESTED_MSG" | jq -c '.quote')
MSG=$(echo "$ATTESTED_MSG" | jq 'del(.quote)')
if [ -n "$MOCK_SGX" ]; then
case "$REQUEST" in
"Instantiate")
jq -nc --argjson msg "$MSG" --argjson "attestation" \
"$QUOTE" \
'$ARGS.named' ;;
"SessionCreate" | "SessionSetPubKey")
REQUEST_KEY=$(echo "$REQUEST" | perl -pe 's/([A-Z])/_\L$1/g;s/^_//') #sed 's/\([A-Z]\)/_\L\1/g;s/^_//')
jq -nc --argjson quartz "$(jq -nc --argjson "$REQUEST_KEY" "$(jq -nc --argjson msg "$MSG" --argjson attestation \
"$QUOTE" '$ARGS.named')" '$ARGS.named')" '$ARGS.named' ;;
*)
usage ;;
esac
exit
fi
# clear tmp files from previous runs
rm -f "$QUOTE_FILE" "$REPORT_FILE" "$REPORT_SIG_FILE"
# request the IAS report for EPID attestations
echo -n "$QUOTE" | xxd -r -p - > "$QUOTE_FILE"
gramine-sgx-ias-request report -g "$RA_CLIENT_SPID" -k "$IAS_API_KEY" -q "$QUOTE_FILE" -r "$REPORT_FILE" -s "$REPORT_SIG_FILE" > /dev/null 2>&1
@ -44,17 +64,17 @@ REPORTSIG=$(cat "$REPORT_SIG_FILE" | tr -d '\r')
#echo "$REPORTSIG"
case "$REQUEST" in
"Instantiate")
jq -nc --argjson msg "$MSG" --argjson "attestation" \
"$(jq -nc --argjson report "$(jq -nc --argjson report "$REPORT" --arg reportsig "$REPORTSIG" '$ARGS.named')" '$ARGS.named')" \
'$ARGS.named' ;;
"Instantiate")
jq -nc --argjson msg "$MSG" --argjson "attestation" \
"$(jq -nc --argjson report "$(jq -nc --argjson report "$REPORT" --arg reportsig "$REPORTSIG" '$ARGS.named')" '$ARGS.named')" \
'$ARGS.named' ;;
"SessionCreate" | "SessionSetPubKey")
REQUEST_KEY=$(echo "$REQUEST" | sed 's/\([A-Z]\)/_\L\1/g;s/^_//')
jq -nc --argjson quartz "$(jq -nc --argjson "$REQUEST_KEY" "$(jq -nc --argjson msg "$MSG" --argjson attestation \
"$(jq -nc --argjson report "$(jq -nc --argjson report "$REPORT" --arg reportsig "$REPORTSIG" '$ARGS.named')" '$ARGS.named')" \
'$ARGS.named')" '$ARGS.named')" '$ARGS.named' ;;
REQUEST_KEY=$(echo "$REQUEST" | perl -pe 's/([A-Z])/_\L$1/g;s/^_//')
jq -nc --argjson quartz "$(jq -nc --argjson "$REQUEST_KEY" "$(jq -nc --argjson msg "$MSG" --argjson attestation \
"$(jq -nc --argjson report "$(jq -nc --argjson report "$REPORT" --arg reportsig "$REPORTSIG" '$ARGS.named')" '$ARGS.named')" \
'$ARGS.named')" '$ARGS.named')" '$ARGS.named' ;;
*)
usage ;;
*)
usage ;;
esac

View file

@ -1,11 +1,6 @@
mod cli;
use std::{
error::Error,
fs::{read_to_string, File},
io::{Read, Write},
process::Command,
};
use std::{error::Error, fs::File, io::Read};
use clap::Parser;
use cosmos_sdk_proto::{
@ -30,14 +25,12 @@ use cosmrs::{
};
use ecies::{PublicKey, SecretKey};
use quartz_cw::msg::{
execute::attested::{Attested, EpidAttestation},
execute::attested::Attested,
instantiate::{CoreInstantiate, RawInstantiate},
InstantiateMsg,
};
use quartz_proto::quartz::{core_client::CoreClient, InstantiateRequest};
use quartz_relayer::types::InstantiateResponse;
use quartz_tee_ra::IASReport;
use serde_json::{json, Value};
use subtle_encoding::base64;
use tendermint::public_key::Secp256k1 as TmPublicKey;
@ -50,16 +43,32 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = CoreClient::connect(args.enclave_addr.uri().to_string()).await?;
let response = client.instantiate(InstantiateRequest {}).await?;
let response: InstantiateResponse = response.into_inner().try_into()?;
let (config, quote) = response.into_message().into_tuple();
let ias_report = gramine_sgx_ias_report(&quote)?;
println!(
"{}",
serde_json::to_string(&ias_report).expect("infallible serializer")
#[cfg(feature = "mock-sgx")]
let attestation = {
use quartz_cw::msg::execute::attested::MockAttestation;
MockAttestation::default()
};
#[cfg(not(feature = "mock-sgx"))]
let attestation = {
use quartz_cw::msg::execute::attested::EpidAttestation;
use quartz_tee_ra::IASReport;
let ias_report = gramine_sgx_ias_report(response.quote())?;
println!(
"{}",
serde_json::to_string(&ias_report).expect("infallible serializer")
);
let ias_report: IASReport = serde_json::from_str(&ias_report.to_string())?;
EpidAttestation::new(ias_report)
};
let cw_instantiate_msg = Attested::new(
CoreInstantiate::new(response.into_message().into_tuple().0),
attestation,
);
let ias_report: IASReport = serde_json::from_str(&ias_report.to_string())?;
let attestation = EpidAttestation::new(ias_report);
let cw_instantiate_msg = Attested::new(CoreInstantiate::new(config), attestation);
// Read the TSP secret
let secret = {
@ -152,7 +161,14 @@ pub async fn send_tx(node: impl ToString, tx_bytes: Vec<u8>) -> Result<(), Box<d
Ok(())
}
fn gramine_sgx_ias_report(quote: &[u8]) -> Result<Value, Box<dyn Error>> {
#[cfg(not(feature = "mock-sgx"))]
fn gramine_sgx_ias_report(quote: &[u8]) -> Result<serde_json::Value, Box<dyn Error>> {
use std::{
fs::{read_to_string, File},
io::Write,
process::Command,
};
let dir = tempfile::tempdir()?;
let quote_file_path = dir.path().join("test.quote");
let datareport_file_path = dir.path().join("datareport");
@ -173,6 +189,6 @@ fn gramine_sgx_ias_report(quote: &[u8]) -> Result<Value, Box<dyn Error>> {
let report = read_to_string(datareport_file_path)?;
let report_sig = read_to_string(datareportsig_file_path)?;
let ias_report = json!({"report": report, "reportsig": report_sig});
let ias_report = serde_json::json!({"report": report, "reportsig": report_sig});
Ok(ias_report)
}