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", "quartz-proto",
"serde", "serde",
"serde_json", "serde_json",
"sha2 0.10.8",
"tendermint 0.36.0", "tendermint 0.36.0",
"tendermint-light-client", "tendermint-light-client",
"thiserror", "thiserror",

View file

@ -19,6 +19,9 @@ panic = 'abort'
incremental = false incremental = false
overflow-checks = true overflow-checks = true
[features]
mock-sgx = ["quartz-cw/mock-sgx"]
[dependencies] [dependencies]
# external # external
hex = { version = "0.4.3", default-features = false } 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_schema::{cw_serde, QueryResponses};
use cosmwasm_std::{HexBinary, Uint64}; use cosmwasm_std::{HexBinary, Uint64};
use quartz_cw::{ use quartz_cw::{
msg::execute::attested::{RawAttested, RawAttestedMsgSansHandler, RawEpidAttestation}, msg::execute::attested::{RawAttested, RawAttestedMsgSansHandler, RawDefaultAttestation},
prelude::*, prelude::*,
}; };
use crate::state::{RawHash, SettleOff}; use crate::state::{RawHash, SettleOff};
type AttestedMsg<M> = RawAttested<RawAttestedMsgSansHandler<M>, RawEpidAttestation>; type AttestedMsg<M, RA> = RawAttested<RawAttestedMsgSansHandler<M>, RA>;
#[cw_serde] #[cw_serde]
pub struct InstantiateMsg(pub QuartzInstantiateMsg); pub struct InstantiateMsg<RA = RawDefaultAttestation>(pub QuartzInstantiateMsg<RA>);
#[cw_serde] #[cw_serde]
#[allow(clippy::large_enum_variant)] #[allow(clippy::large_enum_variant)]
pub enum ExecuteMsg { pub enum ExecuteMsg<RA = RawDefaultAttestation> {
Quartz(QuartzExecuteMsg), Quartz(QuartzExecuteMsg),
FaucetMint(execute::FaucetMintMsg), FaucetMint(execute::FaucetMintMsg),
Transfer(execute::Cw20Transfer), Transfer(execute::Cw20Transfer),
SubmitObligation(execute::SubmitObligationMsg), SubmitObligation(execute::SubmitObligationMsg),
SubmitObligations(execute::SubmitObligationsMsg), SubmitObligations(execute::SubmitObligationsMsg),
SubmitSetoffs(AttestedMsg<execute::SubmitSetoffsMsg>), SubmitSetoffs(AttestedMsg<execute::SubmitSetoffsMsg, RA>),
InitClearing, InitClearing,
SetLiquiditySources(execute::SetLiquiditySourcesMsg), SetLiquiditySources(execute::SetLiquiditySourcesMsg),
} }

View file

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

View file

@ -28,7 +28,7 @@ use mtcs_server::MtcsService;
use proto::clearing_server::ClearingServer as MtcsServer; use proto::clearing_server::ClearingServer as MtcsServer;
use quartz_cw::state::{Config, LightClientOpts}; use quartz_cw::state::{Config, LightClientOpts};
use quartz_enclave::{ use quartz_enclave::{
attestor::{Attestor, EpidAttestor}, attestor::{Attestor, DefaultAttestor},
server::CoreService, server::CoreService,
}; };
use quartz_proto::quartz::core_server::CoreServer; use quartz_proto::quartz::core_server::CoreServer;
@ -53,8 +53,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
args.max_block_lag, args.max_block_lag,
)?; )?;
let attestor = DefaultAttestor::default();
let config = Config::new( let config = Config::new(
EpidAttestor.mr_enclave()?, attestor.mr_enclave()?,
Duration::from_secs(30 * 24 * 60), Duration::from_secs(30 * 24 * 60),
light_client_opts, light_client_opts,
); );
@ -65,9 +67,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.add_service(CoreServer::new(CoreService::new( .add_service(CoreServer::new(CoreService::new(
config, config,
sk.clone(), 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) .serve(args.rpc_addr)
.await?; .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: Now downgrade rust to v1.76.0:
``` ```
rustup install v1.76.0 rustup install 1.76.0
rustup default v1.76.0 rustup default 1.76.0
``` ```
Check the version with `cargo version`. Check the version with `cargo version`.
@ -61,7 +61,7 @@ git checkout v0.44.0
go install ./cmd/wasmd 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`: 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. 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). 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 Binaries
Build the enclave binary and the smart contract binary: Build the enclave binary and the smart contract binary:

View file

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

View file

@ -1,5 +1,5 @@
use cosmwasm_schema::write_api; use cosmwasm_schema::write_api;
use transfers_contracts::msg::{ExecuteMsg, InstantiateMsg}; use transfers_contract::msg::{ExecuteMsg, InstantiateMsg};
fn main() { fn main() {
write_api! { 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 "" echo ""
while ! $CMD query tx $TX_HASH &> /dev/null; do 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 sleep 1
done done

View file

@ -1,19 +1,19 @@
use cosmwasm_schema::cw_serde; use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Addr, HexBinary, Uint128}; use cosmwasm_std::{Addr, HexBinary, Uint128};
use quartz_cw::{ use quartz_cw::{
msg::execute::attested::{RawAttested, RawEpidAttestation}, msg::execute::attested::{RawAttested, RawDefaultAttestation},
prelude::*, prelude::*,
}; };
#[cw_serde] #[cw_serde]
pub struct InstantiateMsg { pub struct InstantiateMsg<RA = RawDefaultAttestation> {
pub quartz: QuartzInstantiateMsg, pub quartz: QuartzInstantiateMsg<RA>,
pub denom: String, pub denom: String,
} }
#[cw_serde] #[cw_serde]
#[allow(clippy::large_enum_variant)] #[allow(clippy::large_enum_variant)]
pub enum ExecuteMsg { pub enum ExecuteMsg<RA = RawDefaultAttestation> {
// quartz initialization // quartz initialization
Quartz(QuartzExecuteMsg), Quartz(QuartzExecuteMsg),
@ -28,7 +28,7 @@ pub enum ExecuteMsg {
ClearTextTransferRequest(execute::ClearTextTransferRequestMsg), ClearTextTransferRequest(execute::ClearTextTransferRequestMsg),
// enclave msg // enclave msg
Update(RawAttested<execute::RawUpdateMsg, RawEpidAttestation>), Update(RawAttested<execute::RawUpdateMsg, RA>),
} }
pub mod execute { 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" version = "0.1.0"
edition = "2021" edition = "2021"
authors = ["Informal Systems <hello@informal.systems>"] authors = ["Informal Systems <hello@informal.systems>"]
autobins = false default-run = "quartz-app-transfers-enclave"
[[bin]] [[bin]]
name = "encrypt" name = "encrypt"
path = "bin/encrypt.rs" path = "bin/encrypt.rs"
[features]
mock-sgx = ["quartz-cw/mock-sgx", "quartz-enclave/mock-sgx"]
[dependencies] [dependencies]
# external # external
anyhow.workspace = true anyhow.workspace = true
@ -20,6 +23,7 @@ k256.workspace = true
prost.workspace = true prost.workspace = true
serde.workspace = true serde.workspace = true
serde_json.workspace = true serde_json.workspace = true
sha2.workspace = true
thiserror.workspace = true thiserror.workspace = true
tokio.workspace = true tokio.workspace = true
tonic.workspace = true tonic.workspace = true

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -3,16 +3,22 @@
set -eo pipefail set -eo pipefail
ROOT=${ROOT:-$HOME} 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 "--------------------------------------------------------"
echo "building enclave binary" echo "building enclave binary"
cd $ROOT/cycles-quartz/apps/transfers/enclave cd $ROOT/cycles-quartz/apps/transfers/enclave
CARGO_TARGET_DIR=./target cargo build --release CARGO_TARGET_DIR=./target cargo build --release $FEATURES
echo "--------------------------------------------------------" echo "--------------------------------------------------------"
echo "building cosmwasm contract binary" echo "building cosmwasm contract binary"
cd $ROOT/cycles-quartz/apps/transfers/contracts cd $ROOT/cycles-quartz/apps/transfers/contracts
bash build.sh bash build.sh $FEATURES

View file

@ -9,12 +9,13 @@ echo "--------------------------------------------------------"
echo "instantiate" echo "instantiate"
cd $ROOT/cycles-quartz/relayer/ cd $ROOT/cycles-quartz/relayer/
export INSTANTIATE_MSG=$(./scripts/relay.sh Instantiate | jq '{quartz: .} + {denom: "ucosm"}' ) export INSTANTIATE_MSG=$(./scripts/relay.sh Instantiate | jq '{quartz: .} + {denom: "ucosm"}' )
echo $INSTANTIATE_MSG
echo "--------------------------------------------------------" echo "--------------------------------------------------------"
echo "deploy contract" echo "deploy contract"
cd $ROOT/cycles-quartz/apps/transfers/contracts/ 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') export CONTRACT=$(cat output | grep Address | awk '{print $NF}' | sed 's/\x1b\[[0-9;]*m//g')
echo $CONTRACT echo $CONTRACT

View file

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

View file

@ -25,6 +25,14 @@ cd ""$DIR_QUARTZ_APP""
echo "$TRUSTED_HASH" > trusted.hash echo "$TRUSTED_HASH" > trusted.hash
echo "$TRUSTED_HEIGHT" > trusted.height 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 "--------------------------------------------------------"
echo "configure gramine" echo "configure gramine"
cd "$DIR_QUARTZ_ENCLAVE" cd "$DIR_QUARTZ_ENCLAVE"

View file

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

View file

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

View file

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

View file

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

View file

@ -7,7 +7,7 @@ use cosmwasm_std::StdError;
use crate::msg::{ use crate::msg::{
execute::{ execute::{
attested::{Attested, EpidAttestation, RawAttested, RawEpidAttestation}, attested::{Attested, DefaultAttestation, RawAttested, RawDefaultAttestation},
session_create::{RawSessionCreate, SessionCreate}, session_create::{RawSessionCreate, SessionCreate},
session_set_pub_key::{RawSessionSetPubKey, SessionSetPubKey}, session_set_pub_key::{RawSessionSetPubKey, SessionSetPubKey},
}, },
@ -15,13 +15,13 @@ use crate::msg::{
}; };
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Execute<Attestation = EpidAttestation> { pub enum Execute<Attestation = DefaultAttestation> {
SessionCreate(Attested<SessionCreate, Attestation>), SessionCreate(Attested<SessionCreate, Attestation>),
SessionSetPubKey(Attested<SessionSetPubKey, Attestation>), SessionSetPubKey(Attested<SessionSetPubKey, Attestation>),
} }
#[cw_serde] #[cw_serde]
pub enum RawExecute<RawAttestation = RawEpidAttestation> { pub enum RawExecute<RawAttestation = RawDefaultAttestation> {
#[serde(rename = "session_create")] #[serde(rename = "session_create")]
RawSessionCreate(RawAttested<RawSessionCreate, RawAttestation>), RawSessionCreate(RawAttested<RawSessionCreate, RawAttestation>),
#[serde(rename = "session_set_pub_key")] #[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_schema::cw_serde;
use cosmwasm_std::StdError; use cosmwasm_std::{HexBinary, StdError};
use quartz_tee_ra::IASReport; 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::{ use crate::{
msg::HasDomainType, msg::HasDomainType,
state::{MrEnclave, UserData}, state::{MrEnclave, UserData},
@ -137,22 +149,28 @@ impl Attestation for EpidAttestation {
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct MockAttestation; pub struct MockAttestation(pub UserData);
impl Default for MockAttestation {
fn default() -> Self {
Self([0u8; 64])
}
}
#[cw_serde] #[cw_serde]
pub struct RawMockAttestation; pub struct RawMockAttestation(pub HexBinary);
impl TryFrom<RawMockAttestation> for MockAttestation { impl TryFrom<RawMockAttestation> for MockAttestation {
type Error = StdError; type Error = StdError;
fn try_from(_value: RawMockAttestation) -> Result<Self, Self::Error> { fn try_from(value: RawMockAttestation) -> Result<Self, Self::Error> {
Ok(Self) Ok(Self(value.0.to_array()?))
} }
} }
impl From<MockAttestation> for RawMockAttestation { impl From<MockAttestation> for RawMockAttestation {
fn from(_value: MockAttestation) -> Self { fn from(value: MockAttestation) -> Self {
Self Self(value.0.into())
} }
} }
@ -162,13 +180,13 @@ impl HasDomainType for RawMockAttestation {
impl HasUserData for MockAttestation { impl HasUserData for MockAttestation {
fn user_data(&self) -> UserData { fn user_data(&self) -> UserData {
unimplemented!("MockAttestation handler is a noop") self.0
} }
} }
impl Attestation for MockAttestation { impl Attestation for MockAttestation {
fn mr_enclave(&self) -> MrEnclave { 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::{ use crate::{
msg::{ msg::{
execute::attested::{ execute::attested::{
Attested, EpidAttestation, HasUserData, RawAttested, RawEpidAttestation, Attested, DefaultAttestation, HasUserData, RawAttested, RawDefaultAttestation,
}, },
HasDomainType, HasDomainType,
}, },
@ -13,10 +13,10 @@ use crate::{
}; };
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Instantiate<A = EpidAttestation>(pub Attested<CoreInstantiate, A>); pub struct Instantiate<A = DefaultAttestation>(pub Attested<CoreInstantiate, A>);
#[cw_serde] #[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> impl<RA> TryFrom<RawInstantiate<RA>> for Instantiate<RA::DomainType>
where where

View file

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

View file

@ -23,9 +23,6 @@ REQUEST_MSG=${2:-"{}"}
# Use the QUARTZ_PORT environment variable if set, otherwise default to 11090 # Use the QUARTZ_PORT environment variable if set, otherwise default to 11090
QUARTZ_PORT="${QUARTZ_PORT:-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 # 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') 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') QUOTE=$(echo "$ATTESTED_MSG" | jq -c '.quote')
MSG=$(echo "$ATTESTED_MSG" | jq 'del(.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 # request the IAS report for EPID attestations
echo -n "$QUOTE" | xxd -r -p - > "$QUOTE_FILE" 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 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
@ -50,7 +70,7 @@ case "$REQUEST" in
'$ARGS.named' ;; '$ARGS.named' ;;
"SessionCreate" | "SessionSetPubKey") "SessionCreate" | "SessionSetPubKey")
REQUEST_KEY=$(echo "$REQUEST" | sed 's/\([A-Z]\)/_\L\1/g;s/^_//') 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 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')" \ "$(jq -nc --argjson report "$(jq -nc --argjson report "$REPORT" --arg reportsig "$REPORTSIG" '$ARGS.named')" '$ARGS.named')" \
'$ARGS.named')" '$ARGS.named')" '$ARGS.named' ;; '$ARGS.named')" '$ARGS.named')" '$ARGS.named' ;;

View file

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