Merge remote-tracking branch 'bisenzone-cw-mvp/main'
This commit is contained in:
commit
cddfcc0fd1
51 changed files with 2800 additions and 0 deletions
4
bisenzone-cw-mvp/.cargo/config
Normal file
4
bisenzone-cw-mvp/.cargo/config
Normal file
|
@ -0,0 +1,4 @@
|
|||
[alias]
|
||||
wasm = "build --release --lib --target wasm32-unknown-unknown"
|
||||
unit-test = "test --lib"
|
||||
schema = "run --bin schema"
|
89
bisenzone-cw-mvp/.github/workflows/Basic.yml
vendored
Normal file
89
bisenzone-cw-mvp/.github/workflows/Basic.yml
vendored
Normal file
|
@ -0,0 +1,89 @@
|
|||
# Based on https://github.com/actions-rs/example/blob/master/.github/workflows/quickstart.yml
|
||||
|
||||
on: [ push, pull_request ]
|
||||
|
||||
name: Basic
|
||||
|
||||
jobs:
|
||||
|
||||
test:
|
||||
name: Test Suite
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install stable toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: 1.73.0
|
||||
target: wasm32-unknown-unknown
|
||||
override: true
|
||||
|
||||
- name: Run unit tests
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: unit-test
|
||||
args: --locked
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
|
||||
- name: Compile WASM contract
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: wasm
|
||||
args: --locked
|
||||
env:
|
||||
RUSTFLAGS: "-C link-arg=-s"
|
||||
|
||||
lints:
|
||||
name: Lints
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install stable toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: stable
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Run cargo clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
args: -- -D warnings
|
||||
|
||||
- name: Generate Schema (for cofi-karma-game)
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: schema
|
||||
args: --locked -p cofi-karma-game
|
||||
|
||||
- name: Generate Schema (for cw-tee-mtcs)
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: schema
|
||||
args: --locked -p cw-tee-mtcs
|
||||
|
||||
- name: Schema Changes
|
||||
# fails if any changes not committed
|
||||
run: git diff --exit-code schema
|
||||
|
||||
- name: Install nighly toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly
|
||||
override: true
|
||||
components: rustfmt
|
||||
|
||||
- name: Run cargo nightly fmt
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
35
bisenzone-cw-mvp/.github/workflows/Release.yml
vendored
Normal file
35
bisenzone-cw-mvp/.github/workflows/Release.yml
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
name: release wasm
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Install cargo-run-script
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: install
|
||||
args: cargo-run-script
|
||||
- name: Run cargo optimize
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: run-script
|
||||
args: optimize
|
||||
- name: Get release ID
|
||||
id: get_release
|
||||
uses: bruceadams/get-release@v1.2.3
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
- name: Upload optimized wasm
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: ./artifacts/*.wasm
|
||||
tag: ${{ github.ref }}
|
||||
overwrite: true
|
||||
file_glob: true
|
17
bisenzone-cw-mvp/.gitignore
vendored
Normal file
17
bisenzone-cw-mvp/.gitignore
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Build results
|
||||
/artifacts
|
||||
target/
|
||||
schema/
|
||||
|
||||
# Cargo+Git helper file (https://github.com/rust-lang/cargo/blob/0.44.1/src/cargo/sources/git/utils.rs#L320-L327)
|
||||
.cargo-ok
|
||||
|
||||
# Text file backups
|
||||
**/*.rs.bk
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
# IDEs
|
||||
*.iml
|
||||
.idea
|
28
bisenzone-cw-mvp/README.md
Normal file
28
bisenzone-cw-mvp/README.md
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Bisenzone CosmWasm MVP
|
||||
|
||||
CosmWasm smart contracts used in the Bisenzone MVP.
|
||||
|
||||
## Testing instructions
|
||||
|
||||
* Deploy the smart contract on a local wasmd instance
|
||||
(see [Obligation Clearing Mvp: Local setup](https://github.com/informalsystems/obligation-clearing-mvp#local-setup))
|
||||
* Should normally be as simple as running the following scripts ->
|
||||
```bash
|
||||
# terminal-1
|
||||
./scripts/keygen.sh
|
||||
./scripts/init-node.sh
|
||||
./scripts/run-node.sh
|
||||
```
|
||||
```bash
|
||||
# terminal-2
|
||||
./scripts/build-contract.sh
|
||||
./scripts/deploy-contract.sh artifacts/cofi_karma_game.wasm
|
||||
```
|
||||
* Set contract env var (using the output of the `deploy.sh` script) -
|
||||
|
||||
```
|
||||
export CONTRACT="wasm13we0myxwzlpx8l5ark8elw5gj5d59dl6cjkzmt80c5q5cv5rt54qhmta7s"
|
||||
```
|
||||
|
||||
For further instructions, refer to the contract specific READMEs
|
||||
(e.g. [cofi-karma-game README.md](contracts/cofi-karma-game/README.md))
|
63
bisenzone-cw-mvp/contracts/cw-tee-mtcs/Cargo.toml
Normal file
63
bisenzone-cw-mvp/contracts/cw-tee-mtcs/Cargo.toml
Normal file
|
@ -0,0 +1,63 @@
|
|||
[package]
|
||||
name = "cw-tee-mtcs"
|
||||
version = "0.1.0"
|
||||
authors = ["hu55a1n1 <sufialhussaini@gmail.com>"]
|
||||
edition = "2021"
|
||||
|
||||
exclude = [
|
||||
# Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication.
|
||||
"contract.wasm",
|
||||
"hash.txt",
|
||||
]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
debug = false
|
||||
rpath = false
|
||||
lto = true
|
||||
debug-assertions = false
|
||||
codegen-units = 1
|
||||
panic = 'abort'
|
||||
incremental = false
|
||||
overflow-checks = true
|
||||
|
||||
[features]
|
||||
# for more explicit tests, cargo test --features=backtraces
|
||||
backtraces = ["cosmwasm-std/backtraces"]
|
||||
# use library feature to disable all instantiate/execute/query exports
|
||||
library = []
|
||||
|
||||
[package.metadata.scripts]
|
||||
optimize = """docker run --rm -v "$(pwd)":/code \
|
||||
--mount type=volume,source="$(basename "$(pwd)")_cache",target=/target \
|
||||
--mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
|
||||
cosmwasm/rust-optimizer:0.14.0
|
||||
"""
|
||||
|
||||
[dependencies]
|
||||
cosmwasm-schema = "1.5.0"
|
||||
cosmwasm-std = { version = "1.5.0", features = [
|
||||
"cosmwasm_1_3",
|
||||
# Enable this if you only deploy to chains that have CosmWasm 1.4 or higher
|
||||
# "cosmwasm_1_4",
|
||||
] }
|
||||
cw-storage-plus = "1.1.0"
|
||||
cw20-base = { version = "1.1.1", features = ["library"] }
|
||||
cw20 = "1.1.1"
|
||||
cw2 = "1.1.1"
|
||||
hex = { version = "0.4.3", default-features = false }
|
||||
k256 = { version = "0.13.2", default-features = false, features = ["ecdsa"] }
|
||||
schemars = "0.8.15"
|
||||
serde = { version = "1.0.189", default-features = false, features = ["derive"] }
|
||||
thiserror = { version = "1.0.49" }
|
||||
|
||||
quartz-cw = { path = "../../packages/quartz-cw" }
|
||||
|
||||
[dev-dependencies]
|
||||
cw-multi-test = "0.17.0"
|
||||
serde_json = "1.0.113"
|
50
bisenzone-cw-mvp/contracts/cw-tee-mtcs/README.md
Normal file
50
bisenzone-cw-mvp/contracts/cw-tee-mtcs/README.md
Normal file
|
@ -0,0 +1,50 @@
|
|||
# CosmWasm smart contract to support MTCS on TEE
|
||||
|
||||
An implementation of the on-chain component of
|
||||
the [Key managers proposal v1](https://github.com/informalsystems/tee-mtcs/issues/26).
|
||||
|
||||
## Testing instructions
|
||||
|
||||
* Submit a bootstrap key manager request -
|
||||
|
||||
```
|
||||
export EXECUTE='{
|
||||
"bootstrap_key_manager": {
|
||||
"compute_mrenclave": "dc43f8c42d8e5f52c8bbd68f426242153f0be10630ff8cca255129a3ca03d273",
|
||||
"key_manager_mrenclave": "1cf2e52911410fbf3f199056a98d58795a559a2e800933f7fcd13d048462271c",
|
||||
"tcb_info": ""
|
||||
}
|
||||
}'
|
||||
wasmd tx wasm execute "$CONTRACT" "$EXECUTE" --from alice --chain-id testing -y
|
||||
```
|
||||
|
||||
* Query the bootstrap state -
|
||||
|
||||
```
|
||||
wasmd query wasm contract-state raw "$CONTRACT" 7367787374617465 # BIN_HEX('sgx_state')
|
||||
# OR ----
|
||||
wasmd query wasm contract-state smart "$CONTRACT" '{
|
||||
"get_sgx_state": { }
|
||||
}'
|
||||
```
|
||||
|
||||
* Submit a join compute node request -
|
||||
|
||||
```
|
||||
export EXECUTE='{
|
||||
"join_compute_node": {
|
||||
"io_exchange_key": "03E67EF09213633074FB4FBF338643F4F0C574ED60EF11D03422EEB06FA38C8F3F",
|
||||
"address": "wasm10n4dsljyyfp2k2hy6e8vuc9ry32px2egwt5e0m",
|
||||
"nonce": "425d87f8620e1dedeee70590cc55b164b8f01480ee59e0b1da35436a2f7c2777"
|
||||
}
|
||||
}'
|
||||
wasmd tx wasm execute "$CONTRACT" "$EXECUTE" --from alice --chain-id testing -y
|
||||
```
|
||||
|
||||
* Query requests -
|
||||
|
||||
```
|
||||
wasmd query wasm contract-state smart "$CONTRACT" '{
|
||||
"get_requests": { }
|
||||
}'
|
||||
```
|
10
bisenzone-cw-mvp/contracts/cw-tee-mtcs/src/bin/schema.rs
Normal file
10
bisenzone-cw-mvp/contracts/cw-tee-mtcs/src/bin/schema.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
use cosmwasm_schema::write_api;
|
||||
use cw_tee_mtcs::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};
|
||||
|
||||
fn main() {
|
||||
write_api! {
|
||||
instantiate: InstantiateMsg,
|
||||
execute: ExecuteMsg,
|
||||
query: QueryMsg,
|
||||
}
|
||||
}
|
278
bisenzone-cw-mvp/contracts/cw-tee-mtcs/src/contract.rs
Normal file
278
bisenzone-cw-mvp/contracts/cw-tee-mtcs/src/contract.rs
Normal file
|
@ -0,0 +1,278 @@
|
|||
use cosmwasm_std::{
|
||||
entry_point, to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult,
|
||||
Uint128,
|
||||
};
|
||||
use cw2::set_contract_version;
|
||||
use cw20_base::{
|
||||
contract::{execute_mint, query_balance as cw20_query_balance},
|
||||
state::{MinterData, TokenInfo, TOKEN_INFO},
|
||||
};
|
||||
use quartz_cw::{handler::RawHandler, state::EPOCH_COUNTER};
|
||||
|
||||
use crate::{
|
||||
error::ContractError,
|
||||
msg::{
|
||||
execute::{SubmitObligationMsg, SubmitObligationsMsg, SubmitSetoffsMsg},
|
||||
ExecuteMsg, InstantiateMsg, QueryMsg,
|
||||
},
|
||||
state::{
|
||||
current_epoch_key, LiquiditySourcesItem, ObligationsItem, State, LIQUIDITY_SOURCES_KEY,
|
||||
OBLIGATIONS_KEY, STATE,
|
||||
},
|
||||
};
|
||||
|
||||
// version info for migration info
|
||||
const CONTRACT_NAME: &str = "crates.io:cw-tee-mtcs";
|
||||
const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
#[cfg_attr(not(feature = "library"), entry_point)]
|
||||
pub fn instantiate(
|
||||
mut deps: DepsMut,
|
||||
env: Env,
|
||||
info: MessageInfo,
|
||||
msg: InstantiateMsg,
|
||||
) -> Result<Response, ContractError> {
|
||||
// must be the handled first!
|
||||
msg.0.handle_raw(deps.branch(), &env, &info)?;
|
||||
|
||||
let state = State {
|
||||
owner: info.sender.to_string(),
|
||||
};
|
||||
set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
|
||||
STATE.save(deps.storage, &state)?;
|
||||
|
||||
EPOCH_COUNTER.save(deps.storage, &1)?;
|
||||
|
||||
ObligationsItem::new(¤t_epoch_key(OBLIGATIONS_KEY, deps.storage)?)
|
||||
.save(deps.storage, &Default::default())?;
|
||||
|
||||
LiquiditySourcesItem::new(¤t_epoch_key(LIQUIDITY_SOURCES_KEY, deps.storage)?)
|
||||
.save(deps.storage, &Default::default())?;
|
||||
|
||||
// store token info using cw20-base format
|
||||
let data = TokenInfo {
|
||||
name: "USD".to_string(),
|
||||
symbol: "!$".to_string(),
|
||||
decimals: 0,
|
||||
total_supply: Uint128::zero(),
|
||||
// set self as minter, so we can properly execute mint and burn
|
||||
mint: Some(MinterData {
|
||||
minter: env.contract.address.clone(),
|
||||
cap: None,
|
||||
}),
|
||||
};
|
||||
TOKEN_INFO.save(deps.storage, &data)?;
|
||||
|
||||
let info = MessageInfo {
|
||||
sender: env.contract.address.clone(),
|
||||
funds: vec![],
|
||||
};
|
||||
|
||||
execute_mint(
|
||||
deps.branch(),
|
||||
env.clone(),
|
||||
info.clone(),
|
||||
"wasm1qv9nel6lwtrq5jmwruxfndqw7ejskn5ysz53hp".to_owned(),
|
||||
Uint128::new(1000),
|
||||
)?;
|
||||
|
||||
execute_mint(
|
||||
deps.branch(),
|
||||
env.clone(),
|
||||
info.clone(),
|
||||
"wasm1tfxrdcj5kk6rewzmmkku4d9htpjqr0kk6lcftv".to_owned(),
|
||||
Uint128::new(1000),
|
||||
)?;
|
||||
|
||||
execute_mint(
|
||||
deps.branch(),
|
||||
env.clone(),
|
||||
info.clone(),
|
||||
"wasm1gjg72awjl7jvtmq4kjqp3al9p6crstpar8wgn5".to_owned(),
|
||||
Uint128::new(1000),
|
||||
)?;
|
||||
|
||||
Ok(Response::new()
|
||||
.add_attribute("method", "instantiate")
|
||||
.add_attribute("owner", info.sender))
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "library"), entry_point)]
|
||||
pub fn execute(
|
||||
mut deps: DepsMut,
|
||||
env: Env,
|
||||
info: MessageInfo,
|
||||
msg: ExecuteMsg,
|
||||
) -> Result<Response, ContractError> {
|
||||
match msg {
|
||||
ExecuteMsg::Quartz(msg) => msg.handle_raw(deps, &env, &info).map_err(Into::into),
|
||||
ExecuteMsg::SubmitObligation(SubmitObligationMsg { ciphertext, digest }) => {
|
||||
execute::submit_obligation(deps, ciphertext, digest)
|
||||
}
|
||||
ExecuteMsg::SubmitObligations(SubmitObligationsMsg {
|
||||
obligations,
|
||||
liquidity_sources,
|
||||
}) => {
|
||||
for o in obligations {
|
||||
execute::submit_obligation(deps.branch(), o.ciphertext, o.digest)?;
|
||||
}
|
||||
execute::append_liquidity_sources(deps, liquidity_sources)?;
|
||||
Ok(Response::new())
|
||||
}
|
||||
ExecuteMsg::SubmitSetoffs(SubmitSetoffsMsg { setoffs_enc }) => {
|
||||
execute::submit_setoffs(deps, env, info, setoffs_enc)
|
||||
}
|
||||
ExecuteMsg::InitClearing => execute::init_clearing(deps),
|
||||
}
|
||||
}
|
||||
|
||||
pub mod execute {
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use cosmwasm_std::{DepsMut, Env, HexBinary, MessageInfo, Response, StdResult};
|
||||
use cw20_base::contract::{execute_burn, execute_mint};
|
||||
use quartz_cw::state::{Hash, EPOCH_COUNTER};
|
||||
|
||||
use crate::{
|
||||
state::{
|
||||
current_epoch_key, previous_epoch_key, LiquiditySourcesItem, ObligationsItem, RawHash,
|
||||
SetoffsItem, SettleOff, LIQUIDITY_SOURCES_KEY, OBLIGATIONS_KEY, SETOFFS_KEY,
|
||||
},
|
||||
ContractError,
|
||||
};
|
||||
|
||||
pub fn submit_obligation(
|
||||
deps: DepsMut,
|
||||
ciphertext: HexBinary,
|
||||
digest: HexBinary,
|
||||
) -> Result<Response, ContractError> {
|
||||
let _: Hash = digest.to_array()?;
|
||||
|
||||
// store the `(digest, ciphertext)` tuple
|
||||
ObligationsItem::new(¤t_epoch_key(OBLIGATIONS_KEY, deps.storage)?).update(
|
||||
deps.storage,
|
||||
|mut obligations| {
|
||||
if let Some(_duplicate) = obligations.insert(digest.clone(), ciphertext.clone()) {
|
||||
return Err(ContractError::DuplicateEntry);
|
||||
}
|
||||
Ok(obligations)
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(Response::new()
|
||||
.add_attribute("action", "submit_obligation")
|
||||
.add_attribute("digest", digest.to_string())
|
||||
.add_attribute("ciphertext", ciphertext.to_string()))
|
||||
}
|
||||
|
||||
pub fn append_liquidity_sources(
|
||||
deps: DepsMut,
|
||||
liquidity_sources: Vec<String>,
|
||||
) -> Result<(), ContractError> {
|
||||
liquidity_sources
|
||||
.iter()
|
||||
.try_for_each(|ls| deps.api.addr_validate(ls).map(|_| ()))?;
|
||||
|
||||
// store the liquidity sources
|
||||
LiquiditySourcesItem::new(¤t_epoch_key(LIQUIDITY_SOURCES_KEY, deps.storage)?)
|
||||
.update(deps.storage, |mut ls| {
|
||||
ls.extend(liquidity_sources);
|
||||
Ok::<_, ContractError>(ls)
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn submit_setoffs(
|
||||
mut deps: DepsMut,
|
||||
env: Env,
|
||||
_info: MessageInfo,
|
||||
setoffs_enc: BTreeMap<RawHash, SettleOff>,
|
||||
) -> Result<Response, ContractError> {
|
||||
// store the `BTreeMap<RawHash, RawCipherText>`
|
||||
SetoffsItem::new(&previous_epoch_key(SETOFFS_KEY, deps.storage)?)
|
||||
.save(deps.storage, &setoffs_enc)?;
|
||||
|
||||
for (_, so) in setoffs_enc {
|
||||
if let SettleOff::Transfer(t) = so {
|
||||
let info = MessageInfo {
|
||||
sender: env.contract.address.clone(),
|
||||
funds: vec![],
|
||||
};
|
||||
|
||||
execute_mint(
|
||||
deps.branch(),
|
||||
env.clone(),
|
||||
info.clone(),
|
||||
t.payee.to_string(),
|
||||
t.amount.into(),
|
||||
)?;
|
||||
|
||||
let payer = deps.api.addr_validate(&t.payer.to_string())?;
|
||||
let info = MessageInfo {
|
||||
sender: payer,
|
||||
funds: vec![],
|
||||
};
|
||||
|
||||
execute_burn(deps.branch(), env.clone(), info, t.amount.into())?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Response::new().add_attribute("action", "submit_setoffs"))
|
||||
}
|
||||
|
||||
pub fn init_clearing(deps: DepsMut) -> Result<Response, ContractError> {
|
||||
EPOCH_COUNTER.update(deps.storage, |mut counter| -> StdResult<_> {
|
||||
counter += 1;
|
||||
Ok(counter)
|
||||
})?;
|
||||
Ok(Response::new().add_attribute("action", "init_clearing"))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "library"), entry_point)]
|
||||
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
|
||||
match msg {
|
||||
QueryMsg::GetAllSetoffs => to_json_binary(&query::get_all_setoffs(deps)?),
|
||||
QueryMsg::GetLiquiditySources { epoch } => {
|
||||
to_json_binary(&query::get_liquidity_sources(deps, epoch)?)
|
||||
}
|
||||
QueryMsg::Balance { address } => to_json_binary(&cw20_query_balance(deps, address)?),
|
||||
}
|
||||
}
|
||||
|
||||
pub mod query {
|
||||
use cosmwasm_std::{Deps, StdResult};
|
||||
|
||||
use crate::{
|
||||
msg::{GetAllSetoffsResponse, GetLiquiditySourcesResponse},
|
||||
state::{
|
||||
current_epoch_key, epoch_key, previous_epoch_key, LiquiditySourcesItem, SetoffsItem,
|
||||
LIQUIDITY_SOURCES_KEY, SETOFFS_KEY,
|
||||
},
|
||||
};
|
||||
|
||||
pub fn get_all_setoffs(deps: Deps) -> StdResult<GetAllSetoffsResponse> {
|
||||
let setoffs = SetoffsItem::new(&previous_epoch_key(SETOFFS_KEY, deps.storage)?)
|
||||
.load(deps.storage)?
|
||||
.into_iter()
|
||||
.collect();
|
||||
Ok(GetAllSetoffsResponse { setoffs })
|
||||
}
|
||||
|
||||
pub fn get_liquidity_sources(
|
||||
deps: Deps,
|
||||
epoch: Option<usize>,
|
||||
) -> StdResult<GetLiquiditySourcesResponse> {
|
||||
let epoch_key = match epoch {
|
||||
None => current_epoch_key(LIQUIDITY_SOURCES_KEY, deps.storage)?,
|
||||
Some(e) => epoch_key(LIQUIDITY_SOURCES_KEY, e)?,
|
||||
};
|
||||
|
||||
let liquidity_sources = LiquiditySourcesItem::new(&epoch_key)
|
||||
.load(deps.storage)?
|
||||
.into_iter()
|
||||
.collect();
|
||||
Ok(GetLiquiditySourcesResponse { liquidity_sources })
|
||||
}
|
||||
}
|
45
bisenzone-cw-mvp/contracts/cw-tee-mtcs/src/error.rs
Normal file
45
bisenzone-cw-mvp/contracts/cw-tee-mtcs/src/error.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
use cosmwasm_std::StdError;
|
||||
use cw20_base::ContractError as Cw20ContractError;
|
||||
use hex::FromHexError;
|
||||
use k256::ecdsa::Error as K256Error;
|
||||
use quartz_cw::error::Error as QuartzError;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum ContractError {
|
||||
#[error("{0}")]
|
||||
Std(#[from] StdError),
|
||||
|
||||
#[error("{0}")]
|
||||
Quartz(#[from] QuartzError),
|
||||
|
||||
#[error("Unauthorized")]
|
||||
Unauthorized,
|
||||
|
||||
#[error("Duplicate entry found")]
|
||||
DuplicateEntry,
|
||||
|
||||
#[error("Not Secp256K1")]
|
||||
K256(K256Error),
|
||||
|
||||
#[error("Invalid hex")]
|
||||
Hex(#[from] FromHexError),
|
||||
|
||||
#[error("Invalid length")]
|
||||
BadLength,
|
||||
|
||||
#[error("Cw20 error: {0}")]
|
||||
Cw20(Cw20ContractError),
|
||||
}
|
||||
|
||||
impl From<K256Error> for ContractError {
|
||||
fn from(e: K256Error) -> Self {
|
||||
Self::K256(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Cw20ContractError> for ContractError {
|
||||
fn from(e: Cw20ContractError) -> Self {
|
||||
Self::Cw20(e)
|
||||
}
|
||||
}
|
15
bisenzone-cw-mvp/contracts/cw-tee-mtcs/src/lib.rs
Normal file
15
bisenzone-cw-mvp/contracts/cw-tee-mtcs/src/lib.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
#![deny(
|
||||
warnings,
|
||||
trivial_casts,
|
||||
trivial_numeric_casts,
|
||||
unused_import_braces,
|
||||
unused_qualifications
|
||||
)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
pub mod contract;
|
||||
mod error;
|
||||
pub mod msg;
|
||||
pub mod state;
|
||||
|
||||
pub use crate::error::ContractError;
|
166
bisenzone-cw-mvp/contracts/cw-tee-mtcs/src/msg.rs
Normal file
166
bisenzone-cw-mvp/contracts/cw-tee-mtcs/src/msg.rs
Normal file
|
@ -0,0 +1,166 @@
|
|||
use std::collections::BTreeMap;
|
||||
|
||||
use cosmwasm_schema::{cw_serde, QueryResponses};
|
||||
use cosmwasm_std::HexBinary;
|
||||
use quartz_cw::prelude::*;
|
||||
|
||||
use crate::state::{RawHash, SettleOff};
|
||||
|
||||
#[cw_serde]
|
||||
pub struct InstantiateMsg(pub QuartzInstantiateMsg);
|
||||
|
||||
#[cw_serde]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum ExecuteMsg {
|
||||
Quartz(QuartzExecuteMsg),
|
||||
SubmitObligation(execute::SubmitObligationMsg),
|
||||
SubmitObligations(execute::SubmitObligationsMsg),
|
||||
SubmitSetoffs(execute::SubmitSetoffsMsg),
|
||||
InitClearing,
|
||||
}
|
||||
|
||||
pub mod execute {
|
||||
use super::*;
|
||||
|
||||
#[cw_serde]
|
||||
pub struct SubmitObligationMsg {
|
||||
pub ciphertext: HexBinary,
|
||||
pub digest: HexBinary,
|
||||
// pub signatures: [HexBinary; 2],
|
||||
// pub proof: π
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct SubmitObligationsMsg {
|
||||
pub obligations: Vec<SubmitObligationMsg>,
|
||||
pub liquidity_sources: Vec<String>,
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct SubmitTenderMsg {
|
||||
pub ciphertext: HexBinary,
|
||||
pub digest: HexBinary,
|
||||
// pub proof: π
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct SubmitSetoffsMsg {
|
||||
pub setoffs_enc: BTreeMap<RawHash, SettleOff>,
|
||||
// pub proof: π,
|
||||
}
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
#[derive(QueryResponses)]
|
||||
pub enum QueryMsg {
|
||||
#[returns(GetAllSetoffsResponse)]
|
||||
GetAllSetoffs,
|
||||
#[returns(GetLiquiditySourcesResponse)]
|
||||
GetLiquiditySources { epoch: Option<usize> }, // `None` means latest
|
||||
#[returns(cw20::BalanceResponse)]
|
||||
Balance { address: String },
|
||||
}
|
||||
|
||||
// We define a custom struct for each query response
|
||||
#[cw_serde]
|
||||
pub struct GetAllSetoffsResponse {
|
||||
pub setoffs: Vec<(HexBinary, SettleOff)>,
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct GetLiquiditySourcesResponse {
|
||||
pub liquidity_sources: Vec<String>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serde_instantiate_msg() {
|
||||
let _: InstantiateMsg = serde_json::from_str(
|
||||
r#"{
|
||||
"msg": {
|
||||
"config": {
|
||||
"mr_enclave": "1bfb949d235f61e5dc40f874ba3e9c36adef1e7a521b4b5f70e10fb1dc803251",
|
||||
"epoch_duration": {
|
||||
"secs": 43200,
|
||||
"nanos": 0
|
||||
},
|
||||
"light_client_opts": {
|
||||
"chain_id": "testing",
|
||||
"trusted_height": 1,
|
||||
"trusted_hash": "a1d115ba3a5e9fcc12ed68a9d8669159e9085f6f96ec26619f5c7ceb4ee02869",
|
||||
"trust_threshold": [
|
||||
2,
|
||||
3
|
||||
],
|
||||
"trusting_period": 1209600,
|
||||
"max_clock_drift": 5,
|
||||
"max_block_lag": 5
|
||||
}
|
||||
}
|
||||
},
|
||||
"attestation": {
|
||||
"report": {
|
||||
"report": {
|
||||
"id": "5246688123689513540899231107533660789",
|
||||
"timestamp": "2024-02-07T17:06:23.913745",
|
||||
"version": 4,
|
||||
"epidPseudonym": "+CUyIi74LPqS6M0NF7YrSxLqPdX3MKs6D6LIPqRG/ZEB4WmxZVvxAJwdwg/0m9cYnUUQguLnJotthX645lAogfJgO8Xg5/91lSegwyUKvHmKgtjOHX/YTbVe/wmgWiBdaL+KmarY0Je459Px/FqGLWLsAF7egPAJRd1Xn88Znrs=",
|
||||
"advisoryURL": "https://security-center.intel.com",
|
||||
"advisoryIDs": [
|
||||
"INTEL-SA-00161",
|
||||
"INTEL-SA-00219",
|
||||
"INTEL-SA-00289",
|
||||
"INTEL-SA-00334",
|
||||
"INTEL-SA-00615"
|
||||
],
|
||||
"isvEnclaveQuoteStatus": "CONFIGURATION_AND_SW_HARDENING_NEEDED",
|
||||
"platformInfoBlob": "150200650000080000141402040180070000000000000000000D00000C000000020000000000000CB0F08115F3DE71AE97980FE5E10B042054930ACE356C79EC44603D3F890756EC6ED73927A7C58CDE9AF1E754AEC77E335E8D80294407936BEB6404F27669FF7BB1",
|
||||
"isvEnclaveQuoteBody": "AgABALAMAAAPAA8AAAAAAFHK9aSLRQ1iSu/jKG0xSJQAAAAAAAAAAAAAAAAAAAAAFBQCBwGAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAHAAAAAAAAAOPC8qW4QNieBprK/8rbZRDvhmpz06nuVxAO1fhkbuS7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc8uUpEUEPvz8ZkFapjVh5WlWaLoAJM/f80T0EhGInHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRE7C+d+1dDWhoDsdyBrjVh+1AZ5txMhzN1UBeTVSmggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
},
|
||||
"reportsig": "YcY4SPvkfR4P2E8A5huutCeS+vY/ir+xq6disalNfNtAcUyOIOqTPVXhAZgY1M5B47Hjj1oYWf2qC2w+dnj7VcZjzO9oR0pJYdA+A7jaVrNzH2eXA79yICkuU8WE/x58I0j5vjXLoHXahaKlpZkMeTphqBY8u+FTVSdP3cWPho4viPapTfQRuEWmYq4KIq2zSr6wLg3Pz+yQ+G3e9BASVkLYxdYGTDFH1pMmfas9SEI7V4I+j8DaXmL8bucSRakmcQdmDMPGiA7mvIhSAlprzCrdxM7CHeUC6MPLN1fmFFcc9kyO/ved69j/651MWC83GgxSJ15L80U+DQzmrSW8xg=="
|
||||
}
|
||||
}
|
||||
}"#,
|
||||
).expect("failed to deserialize hardcoded quartz instantiate msg");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serde_execute_msg() {
|
||||
let _: ExecuteMsg = serde_json::from_str(
|
||||
r#"{
|
||||
"quartz": {
|
||||
"session_create": {
|
||||
"msg": {
|
||||
"nonce": "425d87f8620e1dedeee70590cc55b164b8f01480ee59e0b1da35436a2f7c2777"
|
||||
},
|
||||
"attestation": {
|
||||
"report": {
|
||||
"report": {
|
||||
"id": "5246688123689513540899231107533660789",
|
||||
"timestamp": "2024-02-07T17:06:23.913745",
|
||||
"version": 4,
|
||||
"epidPseudonym": "+CUyIi74LPqS6M0NF7YrSxLqPdX3MKs6D6LIPqRG/ZEB4WmxZVvxAJwdwg/0m9cYnUUQguLnJotthX645lAogfJgO8Xg5/91lSegwyUKvHmKgtjOHX/YTbVe/wmgWiBdaL+KmarY0Je459Px/FqGLWLsAF7egPAJRd1Xn88Znrs=",
|
||||
"advisoryURL": "https://security-center.intel.com",
|
||||
"advisoryIDs": [
|
||||
"INTEL-SA-00161",
|
||||
"INTEL-SA-00219",
|
||||
"INTEL-SA-00289",
|
||||
"INTEL-SA-00334",
|
||||
"INTEL-SA-00615"
|
||||
],
|
||||
"isvEnclaveQuoteStatus": "CONFIGURATION_AND_SW_HARDENING_NEEDED",
|
||||
"platformInfoBlob": "150200650000080000141402040180070000000000000000000D00000C000000020000000000000CB0F08115F3DE71AE97980FE5E10B042054930ACE356C79EC44603D3F890756EC6ED73927A7C58CDE9AF1E754AEC77E335E8D80294407936BEB6404F27669FF7BB1",
|
||||
"isvEnclaveQuoteBody": "AgABALAMAAAPAA8AAAAAAFHK9aSLRQ1iSu/jKG0xSJQAAAAAAAAAAAAAAAAAAAAAFBQCBwGAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAHAAAAAAAAAOPC8qW4QNieBprK/8rbZRDvhmpz06nuVxAO1fhkbuS7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc8uUpEUEPvz8ZkFapjVh5WlWaLoAJM/f80T0EhGInHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRE7C+d+1dDWhoDsdyBrjVh+1AZ5txMhzN1UBeTVSmggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
},
|
||||
"reportsig": "YcY4SPvkfR4P2E8A5huutCeS+vY/ir+xq6disalNfNtAcUyOIOqTPVXhAZgY1M5B47Hjj1oYWf2qC2w+dnj7VcZjzO9oR0pJYdA+A7jaVrNzH2eXA79yICkuU8WE/x58I0j5vjXLoHXahaKlpZkMeTphqBY8u+FTVSdP3cWPho4viPapTfQRuEWmYq4KIq2zSr6wLg3Pz+yQ+G3e9BASVkLYxdYGTDFH1pMmfas9SEI7V4I+j8DaXmL8bucSRakmcQdmDMPGiA7mvIhSAlprzCrdxM7CHeUC6MPLN1fmFFcc9kyO/ved69j/651MWC83GgxSJ15L80U+DQzmrSW8xg=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}"#,
|
||||
).expect("failed to deserialize hardcoded quartz msg");
|
||||
}
|
||||
}
|
49
bisenzone-cw-mvp/contracts/cw-tee-mtcs/src/state.rs
Normal file
49
bisenzone-cw-mvp/contracts/cw-tee-mtcs/src/state.rs
Normal file
|
@ -0,0 +1,49 @@
|
|||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::{HexBinary, StdError, Storage};
|
||||
use cw_storage_plus::Item;
|
||||
use quartz_cw::state::EPOCH_COUNTER;
|
||||
|
||||
pub type RawHash = HexBinary;
|
||||
pub type RawCipherText = HexBinary;
|
||||
|
||||
pub type ObligationsItem<'a> = Item<'a, BTreeMap<RawHash, RawCipherText>>;
|
||||
pub type SetoffsItem<'a> = Item<'a, BTreeMap<RawHash, SettleOff>>;
|
||||
pub type LiquiditySourcesItem<'a> = Item<'a, BTreeSet<String>>;
|
||||
|
||||
#[cw_serde]
|
||||
pub struct State {
|
||||
pub owner: String,
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct Transfer {
|
||||
pub payer: String,
|
||||
pub payee: String,
|
||||
pub amount: u64,
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
#[serde(untagged)]
|
||||
pub enum SettleOff {
|
||||
SetOff(Vec<RawCipherText>),
|
||||
Transfer(Transfer),
|
||||
}
|
||||
|
||||
pub const STATE: Item<State> = Item::new("state");
|
||||
pub const OBLIGATIONS_KEY: &str = "obligations";
|
||||
pub const SETOFFS_KEY: &str = "setoffs";
|
||||
pub const LIQUIDITY_SOURCES_KEY: &str = "liquidity_sources";
|
||||
|
||||
pub fn current_epoch_key(key: &str, storage: &dyn Storage) -> Result<String, StdError> {
|
||||
epoch_key(key, EPOCH_COUNTER.load(storage)?)
|
||||
}
|
||||
|
||||
pub fn previous_epoch_key(key: &str, storage: &dyn Storage) -> Result<String, StdError> {
|
||||
epoch_key(key, EPOCH_COUNTER.load(storage)? - 1)
|
||||
}
|
||||
|
||||
pub fn epoch_key(key: &str, epoch: usize) -> Result<String, StdError> {
|
||||
Ok(format!("{}/{key}", epoch))
|
||||
}
|
5
bisenzone-cw-mvp/packages/quartz-cw/.cargo/config
Normal file
5
bisenzone-cw-mvp/packages/quartz-cw/.cargo/config
Normal file
|
@ -0,0 +1,5 @@
|
|||
[alias]
|
||||
wasm = "build --release --lib --target wasm32-unknown-unknown"
|
||||
wasm-debug = "build --lib --target wasm32-unknown-unknown"
|
||||
schema = "run --bin schema"
|
||||
|
20
bisenzone-cw-mvp/packages/quartz-cw/Cargo.toml
Normal file
20
bisenzone-cw-mvp/packages/quartz-cw/Cargo.toml
Normal file
|
@ -0,0 +1,20 @@
|
|||
[package]
|
||||
name = "quartz-cw"
|
||||
version = "0.1.0"
|
||||
authors = ["hu55a1n1 <sufialhussaini@gmail.com>"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
cw-storage-plus = "1.1.0"
|
||||
cosmwasm-schema = "1.4.0"
|
||||
cosmwasm-std = "1.4.0"
|
||||
k256 = { version = "0.13.2", default-features = false, features = ["ecdsa", "alloc"] }
|
||||
serde = { version = "1.0.188", default-features = false, features = ["derive"] }
|
||||
serde_json = "1.0.94"
|
||||
sha2 = "0.10.8"
|
||||
thiserror = "1.0.57"
|
||||
|
||||
quartz-tee-ra = { path = "../../packages/quartz-tee-ra" }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_json = "1.0.113"
|
1
bisenzone-cw-mvp/packages/quartz-cw/README.md
Normal file
1
bisenzone-cw-mvp/packages/quartz-cw/README.md
Normal file
|
@ -0,0 +1 @@
|
|||
# Quartz CosmWasm spec
|
22
bisenzone-cw-mvp/packages/quartz-cw/src/error.rs
Normal file
22
bisenzone-cw-mvp/packages/quartz-cw/src/error.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
use cosmwasm_std::StdError;
|
||||
use k256::ecdsa::Error as K256Error;
|
||||
use quartz_tee_ra::Error as RaVerificationError;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("{0}")]
|
||||
Std(#[from] StdError),
|
||||
#[error("{0}")]
|
||||
RaVerification(#[from] RaVerificationError),
|
||||
#[error("Not Secp256K1")]
|
||||
K256(K256Error),
|
||||
#[error("invalid session nonce or attempt to reset pub_key")]
|
||||
BadSessionTransition,
|
||||
}
|
||||
|
||||
impl From<K256Error> for Error {
|
||||
fn from(e: K256Error) -> Self {
|
||||
Self::K256(e)
|
||||
}
|
||||
}
|
211
bisenzone-cw-mvp/packages/quartz-cw/src/handler.rs
Normal file
211
bisenzone-cw-mvp/packages/quartz-cw/src/handler.rs
Normal file
|
@ -0,0 +1,211 @@
|
|||
pub mod execute;
|
||||
pub mod instantiate;
|
||||
|
||||
use cosmwasm_std::{DepsMut, Env, MessageInfo, Response};
|
||||
|
||||
use crate::{error::Error, msg::HasDomainType};
|
||||
|
||||
pub trait Handler {
|
||||
fn handle(self, deps: DepsMut<'_>, env: &Env, info: &MessageInfo) -> Result<Response, Error>;
|
||||
}
|
||||
|
||||
pub trait RawHandler: HasDomainType {
|
||||
fn handle_raw(
|
||||
self,
|
||||
deps: DepsMut<'_>,
|
||||
env: &Env,
|
||||
info: &MessageInfo,
|
||||
) -> Result<Response, Error>;
|
||||
}
|
||||
|
||||
impl<RM> RawHandler for RM
|
||||
where
|
||||
RM: HasDomainType,
|
||||
RM::DomainType: Handler,
|
||||
{
|
||||
fn handle_raw(
|
||||
self,
|
||||
deps: DepsMut<'_>,
|
||||
env: &Env,
|
||||
info: &MessageInfo,
|
||||
) -> Result<Response, Error> {
|
||||
let execute: RM::DomainType = self.try_into()?;
|
||||
execute.handle(deps, env, info)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use cosmwasm_std::{
|
||||
testing::{mock_dependencies, mock_env, mock_info},
|
||||
DepsMut,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{
|
||||
handler::Handler,
|
||||
msg::{HasDomainType, RawExecuteMsg, RawInstantiateMsg},
|
||||
state::SESSION,
|
||||
};
|
||||
|
||||
fn parse_msg<'a, R>(msg_str: &'a str) -> R::DomainType
|
||||
where
|
||||
R: HasDomainType + Deserialize<'a>,
|
||||
{
|
||||
let raw_msg: R =
|
||||
serde_json::from_str(msg_str).expect("deserialization failure for hard-coded RawMsg");
|
||||
raw_msg.try_into().expect("invalid hard-coded RawMsg")
|
||||
}
|
||||
|
||||
fn handle_msg<'a, R>(mut deps: DepsMut<'_>, msg_str: &'a str)
|
||||
where
|
||||
R: HasDomainType + Deserialize<'a>,
|
||||
R::DomainType: Handler,
|
||||
{
|
||||
let msg = parse_msg::<R>(msg_str);
|
||||
let info = mock_info("creator", &[]);
|
||||
let env = mock_env();
|
||||
let res = msg
|
||||
.handle(deps.branch(), &env, &info)
|
||||
.expect("msg handler failure");
|
||||
|
||||
assert_eq!(0, res.messages.len());
|
||||
}
|
||||
|
||||
fn instantiate(deps: DepsMut<'_>) {
|
||||
handle_msg::<RawInstantiateMsg>(
|
||||
deps,
|
||||
r#"{
|
||||
"msg": {
|
||||
"mr_enclave": "e3c2f2a5b840d89e069acaffcadb6510ef866a73d3a9ee57100ed5f8646ee4bb"
|
||||
},
|
||||
"attestation": {
|
||||
"report": {
|
||||
"report": {
|
||||
"id": "5246688123689513540899231107533660789",
|
||||
"timestamp": "2024-02-07T17:06:23.913745",
|
||||
"version": 4,
|
||||
"epidPseudonym": "+CUyIi74LPqS6M0NF7YrSxLqPdX3MKs6D6LIPqRG/ZEB4WmxZVvxAJwdwg/0m9cYnUUQguLnJotthX645lAogfJgO8Xg5/91lSegwyUKvHmKgtjOHX/YTbVe/wmgWiBdaL+KmarY0Je459Px/FqGLWLsAF7egPAJRd1Xn88Znrs=",
|
||||
"advisoryURL": "https://security-center.intel.com",
|
||||
"advisoryIDs": [
|
||||
"INTEL-SA-00161",
|
||||
"INTEL-SA-00219",
|
||||
"INTEL-SA-00289",
|
||||
"INTEL-SA-00334",
|
||||
"INTEL-SA-00615"
|
||||
],
|
||||
"isvEnclaveQuoteStatus": "CONFIGURATION_AND_SW_HARDENING_NEEDED",
|
||||
"platformInfoBlob": "150200650000080000141402040180070000000000000000000D00000C000000020000000000000CB0F08115F3DE71AE97980FE5E10B042054930ACE356C79EC44603D3F890756EC6ED73927A7C58CDE9AF1E754AEC77E335E8D80294407936BEB6404F27669FF7BB1",
|
||||
"isvEnclaveQuoteBody": "AgABALAMAAAPAA8AAAAAAFHK9aSLRQ1iSu/jKG0xSJQAAAAAAAAAAAAAAAAAAAAAFBQCBwGAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAHAAAAAAAAAOPC8qW4QNieBprK/8rbZRDvhmpz06nuVxAO1fhkbuS7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc8uUpEUEPvz8ZkFapjVh5WlWaLoAJM/f80T0EhGInHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRE7C+d+1dDWhoDsdyBrjVh+1AZ5txMhzN1UBeTVSmggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
},
|
||||
"reportsig": "YcY4SPvkfR4P2E8A5huutCeS+vY/ir+xq6disalNfNtAcUyOIOqTPVXhAZgY1M5B47Hjj1oYWf2qC2w+dnj7VcZjzO9oR0pJYdA+A7jaVrNzH2eXA79yICkuU8WE/x58I0j5vjXLoHXahaKlpZkMeTphqBY8u+FTVSdP3cWPho4viPapTfQRuEWmYq4KIq2zSr6wLg3Pz+yQ+G3e9BASVkLYxdYGTDFH1pMmfas9SEI7V4I+j8DaXmL8bucSRakmcQdmDMPGiA7mvIhSAlprzCrdxM7CHeUC6MPLN1fmFFcc9kyO/ved69j/651MWC83GgxSJ15L80U+DQzmrSW8xg=="
|
||||
},
|
||||
"mr_enclave": "e3c2f2a5b840d89e069acaffcadb6510ef866a73d3a9ee57100ed5f8646ee4bb",
|
||||
"user_data": "9113b0be77ed5d0d68680ec77206b8d587ed40679b71321ccdd5405e4d54a6820000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
}"#,
|
||||
);
|
||||
}
|
||||
|
||||
fn session_create(deps: DepsMut<'_>) {
|
||||
handle_msg::<RawExecuteMsg>(
|
||||
deps,
|
||||
r#"{
|
||||
"session_create": {
|
||||
"msg": {
|
||||
"nonce": "425d87f8620e1dedeee70590cc55b164b8f01480ee59e0b1da35436a2f7c2777"
|
||||
},
|
||||
"attestation": {
|
||||
"report": {
|
||||
"report": {
|
||||
"id": "5246688123689513540899231107533660789",
|
||||
"timestamp": "2024-02-07T17:06:23.913745",
|
||||
"version": 4,
|
||||
"epidPseudonym": "+CUyIi74LPqS6M0NF7YrSxLqPdX3MKs6D6LIPqRG/ZEB4WmxZVvxAJwdwg/0m9cYnUUQguLnJotthX645lAogfJgO8Xg5/91lSegwyUKvHmKgtjOHX/YTbVe/wmgWiBdaL+KmarY0Je459Px/FqGLWLsAF7egPAJRd1Xn88Znrs=",
|
||||
"advisoryURL": "https://security-center.intel.com",
|
||||
"advisoryIDs": [
|
||||
"INTEL-SA-00161",
|
||||
"INTEL-SA-00219",
|
||||
"INTEL-SA-00289",
|
||||
"INTEL-SA-00334",
|
||||
"INTEL-SA-00615"
|
||||
],
|
||||
"isvEnclaveQuoteStatus": "CONFIGURATION_AND_SW_HARDENING_NEEDED",
|
||||
"platformInfoBlob": "150200650000080000141402040180070000000000000000000D00000C000000020000000000000CB0F08115F3DE71AE97980FE5E10B042054930ACE356C79EC44603D3F890756EC6ED73927A7C58CDE9AF1E754AEC77E335E8D80294407936BEB6404F27669FF7BB1",
|
||||
"isvEnclaveQuoteBody": "AgABALAMAAAPAA8AAAAAAFHK9aSLRQ1iSu/jKG0xSJQAAAAAAAAAAAAAAAAAAAAAFBQCBwGAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAHAAAAAAAAAOPC8qW4QNieBprK/8rbZRDvhmpz06nuVxAO1fhkbuS7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc8uUpEUEPvz8ZkFapjVh5WlWaLoAJM/f80T0EhGInHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRE7C+d+1dDWhoDsdyBrjVh+1AZ5txMhzN1UBeTVSmggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
},
|
||||
"reportsig": "YcY4SPvkfR4P2E8A5huutCeS+vY/ir+xq6disalNfNtAcUyOIOqTPVXhAZgY1M5B47Hjj1oYWf2qC2w+dnj7VcZjzO9oR0pJYdA+A7jaVrNzH2eXA79yICkuU8WE/x58I0j5vjXLoHXahaKlpZkMeTphqBY8u+FTVSdP3cWPho4viPapTfQRuEWmYq4KIq2zSr6wLg3Pz+yQ+G3e9BASVkLYxdYGTDFH1pMmfas9SEI7V4I+j8DaXmL8bucSRakmcQdmDMPGiA7mvIhSAlprzCrdxM7CHeUC6MPLN1fmFFcc9kyO/ved69j/651MWC83GgxSJ15L80U+DQzmrSW8xg=="
|
||||
},
|
||||
"mr_enclave": "e3c2f2a5b840d89e069acaffcadb6510ef866a73d3a9ee57100ed5f8646ee4bb",
|
||||
"user_data": "425d87f8620e1dedeee70590cc55b164b8f01480ee59e0b1da35436a2f7c27770000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
}
|
||||
}"#,
|
||||
);
|
||||
}
|
||||
|
||||
fn session_set_pub_key(deps: DepsMut<'_>) {
|
||||
handle_msg::<RawExecuteMsg>(
|
||||
deps,
|
||||
r#"{
|
||||
"session_set_pub_key": {
|
||||
"msg": {
|
||||
"nonce": "425d87f8620e1dedeee70590cc55b164b8f01480ee59e0b1da35436a2f7c2777"
|
||||
"pub_key": "03E67EF09213633074FB4FBF338643F4F0C574ED60EF11D03422EEB06FA38C8F3F"
|
||||
},
|
||||
"attestation": {
|
||||
"report": {
|
||||
"report": {
|
||||
"id": "5246688123689513540899231107533660789",
|
||||
"timestamp": "2024-02-07T17:06:23.913745",
|
||||
"version": 4,
|
||||
"epidPseudonym": "+CUyIi74LPqS6M0NF7YrSxLqPdX3MKs6D6LIPqRG/ZEB4WmxZVvxAJwdwg/0m9cYnUUQguLnJotthX645lAogfJgO8Xg5/91lSegwyUKvHmKgtjOHX/YTbVe/wmgWiBdaL+KmarY0Je459Px/FqGLWLsAF7egPAJRd1Xn88Znrs=",
|
||||
"advisoryURL": "https://security-center.intel.com",
|
||||
"advisoryIDs": [
|
||||
"INTEL-SA-00161",
|
||||
"INTEL-SA-00219",
|
||||
"INTEL-SA-00289",
|
||||
"INTEL-SA-00334",
|
||||
"INTEL-SA-00615"
|
||||
],
|
||||
"isvEnclaveQuoteStatus": "CONFIGURATION_AND_SW_HARDENING_NEEDED",
|
||||
"platformInfoBlob": "150200650000080000141402040180070000000000000000000D00000C000000020000000000000CB0F08115F3DE71AE97980FE5E10B042054930ACE356C79EC44603D3F890756EC6ED73927A7C58CDE9AF1E754AEC77E335E8D80294407936BEB6404F27669FF7BB1",
|
||||
"isvEnclaveQuoteBody": "AgABALAMAAAPAA8AAAAAAFHK9aSLRQ1iSu/jKG0xSJQAAAAAAAAAAAAAAAAAAAAAFBQCBwGAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAHAAAAAAAAAOPC8qW4QNieBprK/8rbZRDvhmpz06nuVxAO1fhkbuS7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc8uUpEUEPvz8ZkFapjVh5WlWaLoAJM/f80T0EhGInHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRE7C+d+1dDWhoDsdyBrjVh+1AZ5txMhzN1UBeTVSmggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
},
|
||||
"reportsig": "YcY4SPvkfR4P2E8A5huutCeS+vY/ir+xq6disalNfNtAcUyOIOqTPVXhAZgY1M5B47Hjj1oYWf2qC2w+dnj7VcZjzO9oR0pJYdA+A7jaVrNzH2eXA79yICkuU8WE/x58I0j5vjXLoHXahaKlpZkMeTphqBY8u+FTVSdP3cWPho4viPapTfQRuEWmYq4KIq2zSr6wLg3Pz+yQ+G3e9BASVkLYxdYGTDFH1pMmfas9SEI7V4I+j8DaXmL8bucSRakmcQdmDMPGiA7mvIhSAlprzCrdxM7CHeUC6MPLN1fmFFcc9kyO/ved69j/651MWC83GgxSJ15L80U+DQzmrSW8xg=="
|
||||
},
|
||||
"mr_enclave": "e3c2f2a5b840d89e069acaffcadb6510ef866a73d3a9ee57100ed5f8646ee4bb",
|
||||
"user_data": "425d87f8620e1dedeee70590cc55b164b8f01480ee59e0b1da35436a2f7c27770000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
}
|
||||
}"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_instantiate_handler() {
|
||||
let mut deps = mock_dependencies();
|
||||
instantiate(deps.as_mut());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_session_create_handler() {
|
||||
let mut deps = mock_dependencies();
|
||||
instantiate(deps.as_mut());
|
||||
session_create(deps.as_mut());
|
||||
SESSION.load(&deps.storage).expect("Session not created");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_session_set_pub_key_handler() {
|
||||
let mut deps = mock_dependencies();
|
||||
instantiate(deps.as_mut());
|
||||
session_create(deps.as_mut());
|
||||
session_set_pub_key(deps.as_mut());
|
||||
SESSION.load(&deps.storage).expect("Session not created");
|
||||
// TODO(hu55a1n1): check that nonce & pub_key match, etc.
|
||||
}
|
||||
}
|
26
bisenzone-cw-mvp/packages/quartz-cw/src/handler/execute.rs
Normal file
26
bisenzone-cw-mvp/packages/quartz-cw/src/handler/execute.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
pub mod attested;
|
||||
pub mod session_create;
|
||||
pub mod session_set_pub_key;
|
||||
|
||||
use cosmwasm_std::{DepsMut, Env, MessageInfo, Response};
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
handler::Handler,
|
||||
msg::execute::{
|
||||
attested::{Attestation, HasUserData},
|
||||
Execute,
|
||||
},
|
||||
};
|
||||
|
||||
impl<A> Handler for Execute<A>
|
||||
where
|
||||
A: Handler + HasUserData + Attestation,
|
||||
{
|
||||
fn handle(self, deps: DepsMut<'_>, env: &Env, info: &MessageInfo) -> Result<Response, Error> {
|
||||
match self {
|
||||
Execute::SessionCreate(msg) => msg.handle(deps, env, info),
|
||||
Execute::SessionSetPubKey(msg) => msg.handle(deps, env, info),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
use cosmwasm_std::{DepsMut, Env, MessageInfo, Response};
|
||||
use quartz_tee_ra::{verify_epid_attestation, Error as RaVerificationError};
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
handler::Handler,
|
||||
msg::execute::attested::{
|
||||
Attestation, Attested, EpidAttestation, HasUserData, MockAttestation,
|
||||
},
|
||||
state::CONFIG,
|
||||
};
|
||||
|
||||
impl Handler for EpidAttestation {
|
||||
fn handle(
|
||||
self,
|
||||
_deps: DepsMut<'_>,
|
||||
_env: &Env,
|
||||
_info: &MessageInfo,
|
||||
) -> Result<Response, Error> {
|
||||
// attestation handler MUST verify that the user_data and mr_enclave match the config/msg
|
||||
verify_epid_attestation(
|
||||
self.clone().into_report(),
|
||||
self.mr_enclave(),
|
||||
self.user_data(),
|
||||
)
|
||||
.map(|_| Response::default())
|
||||
.map_err(Error::RaVerification)
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler for MockAttestation {
|
||||
fn handle(
|
||||
self,
|
||||
_deps: DepsMut<'_>,
|
||||
_env: &Env,
|
||||
_info: &MessageInfo,
|
||||
) -> Result<Response, Error> {
|
||||
Ok(Response::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, A> Handler for Attested<M, A>
|
||||
where
|
||||
M: Handler + HasUserData,
|
||||
A: Handler + HasUserData + Attestation,
|
||||
{
|
||||
fn handle(
|
||||
self,
|
||||
mut deps: DepsMut<'_>,
|
||||
env: &Env,
|
||||
info: &MessageInfo,
|
||||
) -> Result<Response, Error> {
|
||||
let (msg, attestation) = self.into_tuple();
|
||||
if msg.user_data() != attestation.user_data() {
|
||||
return Err(RaVerificationError::UserDataMismatch.into());
|
||||
}
|
||||
|
||||
if let Some(config) = CONFIG.may_load(deps.storage)? {
|
||||
// if we weren't able to load then the context was from InstantiateMsg so we don't fail
|
||||
// in such cases, the InstantiateMsg handler will verify that the mr_enclave matches
|
||||
if config.mr_enclave() != attestation.mr_enclave() {
|
||||
return Err(RaVerificationError::MrEnclaveMismatch.into());
|
||||
}
|
||||
}
|
||||
|
||||
// handle message first, this has 2 benefits -
|
||||
// 1. we avoid (the more expensive) attestation verification if the message handler fails
|
||||
// 2. we allow the message handler to make changes to the config so that the attestation
|
||||
// handler can use those changes, e.g. InstantiateMsg
|
||||
Handler::handle(msg, deps.branch(), env, info)?;
|
||||
Handler::handle(attestation, deps, env, info)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
use cosmwasm_std::{DepsMut, Env, MessageInfo, Response};
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
handler::Handler,
|
||||
msg::execute::session_create::SessionCreate,
|
||||
state::{Session, SESSION},
|
||||
};
|
||||
|
||||
impl Handler for SessionCreate {
|
||||
fn handle(self, deps: DepsMut<'_>, _env: &Env, _info: &MessageInfo) -> Result<Response, Error> {
|
||||
// TODO(hu55a1n1): overwrite previous session?
|
||||
SESSION
|
||||
.save(deps.storage, &Session::create(self.into_nonce()))
|
||||
.map_err(Error::Std)?;
|
||||
|
||||
Ok(Response::new().add_attribute("action", "session_create"))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
use cosmwasm_std::{DepsMut, Env, HexBinary, MessageInfo, Response};
|
||||
|
||||
use crate::{
|
||||
error::Error, handler::Handler, msg::execute::session_set_pub_key::SessionSetPubKey,
|
||||
state::SESSION,
|
||||
};
|
||||
|
||||
impl Handler for SessionSetPubKey {
|
||||
fn handle(self, deps: DepsMut<'_>, _env: &Env, _info: &MessageInfo) -> Result<Response, Error> {
|
||||
let session = SESSION.load(deps.storage).map_err(Error::Std)?;
|
||||
let (nonce, pub_key) = self.into_tuple();
|
||||
let session = session
|
||||
.with_pub_key(nonce, pub_key)
|
||||
.ok_or(Error::BadSessionTransition)?;
|
||||
|
||||
SESSION.save(deps.storage, &session).map_err(Error::Std)?;
|
||||
|
||||
Ok(Response::new()
|
||||
.add_attribute("action", "session_set_pub_key")
|
||||
.add_attribute(
|
||||
"pub_key",
|
||||
HexBinary::from(pub_key.to_sec1_bytes().into_vec()).to_hex(),
|
||||
))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
use cosmwasm_std::{DepsMut, Env, MessageInfo, Response};
|
||||
use quartz_tee_ra::Error as RaVerificationError;
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
handler::Handler,
|
||||
msg::{
|
||||
execute::attested::{Attestation, EpidAttestation, MockAttestation},
|
||||
instantiate::{CoreInstantiate, Instantiate},
|
||||
},
|
||||
state::{RawConfig, CONFIG, EPOCH_COUNTER},
|
||||
};
|
||||
|
||||
impl Handler for Instantiate<EpidAttestation> {
|
||||
fn handle(self, deps: DepsMut<'_>, env: &Env, info: &MessageInfo) -> Result<Response, Error> {
|
||||
if self.0.msg().config().mr_enclave() != self.0.attestation().mr_enclave() {
|
||||
return Err(RaVerificationError::MrEnclaveMismatch.into());
|
||||
}
|
||||
self.0.handle(deps, env, info)
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler for Instantiate<MockAttestation> {
|
||||
fn handle(self, deps: DepsMut<'_>, env: &Env, info: &MessageInfo) -> Result<Response, Error> {
|
||||
self.0.handle(deps, env, info)
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler for CoreInstantiate {
|
||||
fn handle(self, deps: DepsMut<'_>, _env: &Env, _info: &MessageInfo) -> Result<Response, Error> {
|
||||
CONFIG
|
||||
.save(deps.storage, &RawConfig::from(self.config().clone()))
|
||||
.map_err(Error::Std)?;
|
||||
|
||||
EPOCH_COUNTER.save(deps.storage, &1).map_err(Error::Std)?;
|
||||
|
||||
Ok(Response::new().add_attribute("action", "instantiate"))
|
||||
}
|
||||
}
|
22
bisenzone-cw-mvp/packages/quartz-cw/src/lib.rs
Normal file
22
bisenzone-cw-mvp/packages/quartz-cw/src/lib.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
#![warn(
|
||||
clippy::checked_conversions,
|
||||
clippy::panic,
|
||||
clippy::panic_in_result_fn,
|
||||
clippy::unwrap_used,
|
||||
rust_2018_idioms,
|
||||
unused_lifetimes
|
||||
)]
|
||||
#![deny(
|
||||
trivial_casts,
|
||||
trivial_numeric_casts,
|
||||
unused_import_braces,
|
||||
unused_qualifications,
|
||||
warnings
|
||||
)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
pub mod error;
|
||||
pub mod handler;
|
||||
pub mod msg;
|
||||
pub mod prelude;
|
||||
pub mod state;
|
11
bisenzone-cw-mvp/packages/quartz-cw/src/msg.rs
Normal file
11
bisenzone-cw-mvp/packages/quartz-cw/src/msg.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
pub mod execute;
|
||||
pub mod instantiate;
|
||||
pub mod query;
|
||||
|
||||
use cosmwasm_std::StdError;
|
||||
pub use execute::{Execute as ExecuteMsg, RawExecute as RawExecuteMsg};
|
||||
pub use instantiate::{Instantiate as InstantiateMsg, RawInstantiate as RawInstantiateMsg};
|
||||
|
||||
pub trait HasDomainType: From<Self::DomainType> {
|
||||
type DomainType: TryFrom<Self, Error = StdError>;
|
||||
}
|
66
bisenzone-cw-mvp/packages/quartz-cw/src/msg/execute.rs
Normal file
66
bisenzone-cw-mvp/packages/quartz-cw/src/msg/execute.rs
Normal file
|
@ -0,0 +1,66 @@
|
|||
pub mod attested;
|
||||
pub mod session_create;
|
||||
pub mod session_set_pub_key;
|
||||
|
||||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::StdError;
|
||||
|
||||
use crate::msg::{
|
||||
execute::{
|
||||
attested::{Attested, EpidAttestation, RawAttested, RawEpidAttestation},
|
||||
session_create::{RawSessionCreate, SessionCreate},
|
||||
session_set_pub_key::{RawSessionSetPubKey, SessionSetPubKey},
|
||||
},
|
||||
HasDomainType,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Execute<Attestation = EpidAttestation> {
|
||||
SessionCreate(Attested<SessionCreate, Attestation>),
|
||||
SessionSetPubKey(Attested<SessionSetPubKey, Attestation>),
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub enum RawExecute<RawAttestation = RawEpidAttestation> {
|
||||
#[serde(rename = "session_create")]
|
||||
RawSessionCreate(RawAttested<RawSessionCreate, RawAttestation>),
|
||||
#[serde(rename = "session_set_pub_key")]
|
||||
RawSessionSetPubKey(RawAttested<RawSessionSetPubKey, RawAttestation>),
|
||||
}
|
||||
|
||||
impl<RA> TryFrom<RawExecute<RA>> for Execute<RA::DomainType>
|
||||
where
|
||||
RA: HasDomainType,
|
||||
{
|
||||
type Error = StdError;
|
||||
|
||||
fn try_from(value: RawExecute<RA>) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
RawExecute::RawSessionCreate(msg) => {
|
||||
Ok(Execute::SessionCreate(TryFrom::try_from(msg)?))
|
||||
}
|
||||
RawExecute::RawSessionSetPubKey(msg) => {
|
||||
Ok(Execute::SessionSetPubKey(TryFrom::try_from(msg)?))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<RA> From<Execute<RA::DomainType>> for RawExecute<RA>
|
||||
where
|
||||
RA: HasDomainType,
|
||||
{
|
||||
fn from(value: Execute<RA::DomainType>) -> Self {
|
||||
match value {
|
||||
Execute::SessionCreate(msg) => RawExecute::RawSessionCreate(From::from(msg)),
|
||||
Execute::SessionSetPubKey(msg) => RawExecute::RawSessionSetPubKey(From::from(msg)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<RA> HasDomainType for RawExecute<RA>
|
||||
where
|
||||
RA: HasDomainType,
|
||||
{
|
||||
type DomainType = Execute<RA::DomainType>;
|
||||
}
|
173
bisenzone-cw-mvp/packages/quartz-cw/src/msg/execute/attested.rs
Normal file
173
bisenzone-cw-mvp/packages/quartz-cw/src/msg/execute/attested.rs
Normal file
|
@ -0,0 +1,173 @@
|
|||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::StdError;
|
||||
use quartz_tee_ra::IASReport;
|
||||
|
||||
use crate::{
|
||||
msg::HasDomainType,
|
||||
state::{MrEnclave, UserData},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Attested<M, A> {
|
||||
msg: M,
|
||||
attestation: A,
|
||||
}
|
||||
|
||||
impl<M, A> Attested<M, A> {
|
||||
pub fn new(msg: M, attestation: A) -> Self {
|
||||
Self { msg, attestation }
|
||||
}
|
||||
|
||||
pub fn into_tuple(self) -> (M, A) {
|
||||
let Attested { msg, attestation } = self;
|
||||
(msg, attestation)
|
||||
}
|
||||
|
||||
pub fn msg(&self) -> &M {
|
||||
&self.msg
|
||||
}
|
||||
|
||||
pub fn attestation(&self) -> &A {
|
||||
&self.attestation
|
||||
}
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct RawAttested<RM, RA> {
|
||||
pub msg: RM,
|
||||
pub attestation: RA,
|
||||
}
|
||||
|
||||
impl<RM, RA> TryFrom<RawAttested<RM, RA>> for Attested<RM::DomainType, RA::DomainType>
|
||||
where
|
||||
RM: HasDomainType,
|
||||
RA: HasDomainType,
|
||||
{
|
||||
type Error = StdError;
|
||||
|
||||
fn try_from(value: RawAttested<RM, RA>) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
msg: value.msg.try_into()?,
|
||||
attestation: value.attestation.try_into()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<RM, RA> From<Attested<RM::DomainType, RA::DomainType>> for RawAttested<RM, RA>
|
||||
where
|
||||
RM: HasDomainType,
|
||||
RA: HasDomainType,
|
||||
{
|
||||
fn from(value: Attested<RM::DomainType, RA::DomainType>) -> Self {
|
||||
Self {
|
||||
msg: value.msg.into(),
|
||||
attestation: value.attestation.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<RM, RA> HasDomainType for RawAttested<RM, RA>
|
||||
where
|
||||
RM: HasDomainType,
|
||||
RA: HasDomainType,
|
||||
{
|
||||
type DomainType = Attested<RM::DomainType, RA::DomainType>;
|
||||
}
|
||||
|
||||
pub trait HasUserData {
|
||||
fn user_data(&self) -> UserData;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct EpidAttestation {
|
||||
report: IASReport,
|
||||
}
|
||||
|
||||
impl EpidAttestation {
|
||||
pub fn new(report: IASReport) -> Self {
|
||||
Self { report }
|
||||
}
|
||||
|
||||
pub fn into_report(self) -> IASReport {
|
||||
self.report
|
||||
}
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct RawEpidAttestation {
|
||||
report: IASReport,
|
||||
}
|
||||
|
||||
impl TryFrom<RawEpidAttestation> for EpidAttestation {
|
||||
type Error = StdError;
|
||||
|
||||
fn try_from(value: RawEpidAttestation) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
report: value.report,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EpidAttestation> for RawEpidAttestation {
|
||||
fn from(value: EpidAttestation) -> Self {
|
||||
Self {
|
||||
report: value.report,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HasDomainType for RawEpidAttestation {
|
||||
type DomainType = EpidAttestation;
|
||||
}
|
||||
|
||||
impl HasUserData for EpidAttestation {
|
||||
fn user_data(&self) -> UserData {
|
||||
self.report.report.isv_enclave_quote_body.user_data()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Attestation {
|
||||
fn mr_enclave(&self) -> MrEnclave;
|
||||
}
|
||||
|
||||
impl Attestation for EpidAttestation {
|
||||
fn mr_enclave(&self) -> MrEnclave {
|
||||
self.report.report.isv_enclave_quote_body.mrenclave()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct MockAttestation;
|
||||
|
||||
#[cw_serde]
|
||||
pub struct RawMockAttestation;
|
||||
|
||||
impl TryFrom<RawMockAttestation> for MockAttestation {
|
||||
type Error = StdError;
|
||||
|
||||
fn try_from(_value: RawMockAttestation) -> Result<Self, Self::Error> {
|
||||
Ok(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MockAttestation> for RawMockAttestation {
|
||||
fn from(_value: MockAttestation) -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl HasDomainType for RawMockAttestation {
|
||||
type DomainType = MockAttestation;
|
||||
}
|
||||
|
||||
impl HasUserData for MockAttestation {
|
||||
fn user_data(&self) -> UserData {
|
||||
unimplemented!("MockAttestation handler is a noop")
|
||||
}
|
||||
}
|
||||
|
||||
impl Attestation for MockAttestation {
|
||||
fn mr_enclave(&self) -> MrEnclave {
|
||||
unimplemented!("MockAttestation handler is a noop")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::{HexBinary, StdError};
|
||||
|
||||
use crate::{
|
||||
msg::{execute::attested::HasUserData, HasDomainType},
|
||||
state::{Nonce, UserData},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct SessionCreate {
|
||||
nonce: Nonce,
|
||||
}
|
||||
|
||||
impl SessionCreate {
|
||||
pub fn new(nonce: Nonce) -> Self {
|
||||
Self { nonce }
|
||||
}
|
||||
|
||||
pub fn into_nonce(self) -> Nonce {
|
||||
self.nonce
|
||||
}
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct RawSessionCreate {
|
||||
nonce: HexBinary,
|
||||
}
|
||||
|
||||
impl TryFrom<RawSessionCreate> for SessionCreate {
|
||||
type Error = StdError;
|
||||
|
||||
fn try_from(value: RawSessionCreate) -> Result<Self, Self::Error> {
|
||||
let nonce = value.nonce.to_array()?;
|
||||
Ok(Self { nonce })
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SessionCreate> for RawSessionCreate {
|
||||
fn from(value: SessionCreate) -> Self {
|
||||
Self {
|
||||
nonce: value.nonce.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HasDomainType for RawSessionCreate {
|
||||
type DomainType = SessionCreate;
|
||||
}
|
||||
|
||||
impl HasUserData for SessionCreate {
|
||||
fn user_data(&self) -> UserData {
|
||||
let mut user_data = [0u8; 64];
|
||||
user_data[0..32].copy_from_slice(&self.nonce);
|
||||
user_data
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::{HexBinary, StdError};
|
||||
use k256::ecdsa::VerifyingKey;
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
msg::{execute::attested::HasUserData, HasDomainType},
|
||||
state::{Nonce, UserData},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct SessionSetPubKey {
|
||||
nonce: Nonce,
|
||||
pub_key: VerifyingKey,
|
||||
}
|
||||
|
||||
impl SessionSetPubKey {
|
||||
pub fn new(nonce: Nonce, pub_key: VerifyingKey) -> Self {
|
||||
Self { nonce, pub_key }
|
||||
}
|
||||
|
||||
pub fn into_tuple(self) -> (Nonce, VerifyingKey) {
|
||||
(self.nonce, self.pub_key)
|
||||
}
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct RawSessionSetPubKey {
|
||||
nonce: HexBinary,
|
||||
pub_key: HexBinary,
|
||||
}
|
||||
|
||||
impl TryFrom<RawSessionSetPubKey> for SessionSetPubKey {
|
||||
type Error = StdError;
|
||||
|
||||
fn try_from(value: RawSessionSetPubKey) -> Result<Self, Self::Error> {
|
||||
let nonce = value.nonce.to_array()?;
|
||||
let pub_key = VerifyingKey::from_sec1_bytes(&value.pub_key)
|
||||
.map_err(Error::from)
|
||||
.map_err(|e| StdError::generic_err(e.to_string()))?;
|
||||
Ok(Self { nonce, pub_key })
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SessionSetPubKey> for RawSessionSetPubKey {
|
||||
fn from(value: SessionSetPubKey) -> Self {
|
||||
Self {
|
||||
nonce: value.nonce.into(),
|
||||
pub_key: value.pub_key.to_sec1_bytes().into_vec().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HasDomainType for RawSessionSetPubKey {
|
||||
type DomainType = SessionSetPubKey;
|
||||
}
|
||||
|
||||
impl HasUserData for SessionSetPubKey {
|
||||
fn user_data(&self) -> UserData {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(self.nonce);
|
||||
hasher.update(self.pub_key.to_sec1_bytes());
|
||||
let digest: [u8; 32] = hasher.finalize().into();
|
||||
|
||||
let mut user_data = [0u8; 64];
|
||||
user_data[0..32].copy_from_slice(&digest);
|
||||
user_data
|
||||
}
|
||||
}
|
103
bisenzone-cw-mvp/packages/quartz-cw/src/msg/instantiate.rs
Normal file
103
bisenzone-cw-mvp/packages/quartz-cw/src/msg/instantiate.rs
Normal file
|
@ -0,0 +1,103 @@
|
|||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::StdError;
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
use crate::{
|
||||
msg::{
|
||||
execute::attested::{
|
||||
Attested, EpidAttestation, HasUserData, RawAttested, RawEpidAttestation,
|
||||
},
|
||||
HasDomainType,
|
||||
},
|
||||
state::{Config, RawConfig, UserData},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Instantiate<A = EpidAttestation>(pub Attested<CoreInstantiate, A>);
|
||||
|
||||
#[cw_serde]
|
||||
pub struct RawInstantiate<RA = RawEpidAttestation>(RawAttested<RawCoreInstantiate, RA>);
|
||||
|
||||
impl<RA> TryFrom<RawInstantiate<RA>> for Instantiate<RA::DomainType>
|
||||
where
|
||||
RA: HasDomainType,
|
||||
{
|
||||
type Error = StdError;
|
||||
|
||||
fn try_from(value: RawInstantiate<RA>) -> Result<Self, Self::Error> {
|
||||
Ok(Self(TryFrom::try_from(value.0)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<RA> From<Instantiate<RA::DomainType>> for RawInstantiate<RA>
|
||||
where
|
||||
RA: HasDomainType,
|
||||
{
|
||||
fn from(value: Instantiate<RA::DomainType>) -> Self {
|
||||
Self(From::from(value.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl<RA> HasDomainType for RawInstantiate<RA>
|
||||
where
|
||||
RA: HasDomainType,
|
||||
{
|
||||
type DomainType = Instantiate<RA::DomainType>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct CoreInstantiate {
|
||||
config: Config,
|
||||
}
|
||||
|
||||
impl CoreInstantiate {
|
||||
pub fn new(config: Config) -> Self {
|
||||
Self { config }
|
||||
}
|
||||
|
||||
pub fn config(&self) -> &Config {
|
||||
&self.config
|
||||
}
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct RawCoreInstantiate {
|
||||
config: RawConfig,
|
||||
}
|
||||
|
||||
impl TryFrom<RawCoreInstantiate> for CoreInstantiate {
|
||||
type Error = StdError;
|
||||
|
||||
fn try_from(value: RawCoreInstantiate) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
config: value.config.try_into()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CoreInstantiate> for RawCoreInstantiate {
|
||||
fn from(value: CoreInstantiate) -> Self {
|
||||
Self {
|
||||
config: value.config.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HasDomainType for RawCoreInstantiate {
|
||||
type DomainType = CoreInstantiate;
|
||||
}
|
||||
|
||||
impl HasUserData for CoreInstantiate {
|
||||
fn user_data(&self) -> UserData {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(
|
||||
serde_json::to_string(&RawConfig::from(self.config.clone()))
|
||||
.expect("infallible serializer"),
|
||||
);
|
||||
let digest: [u8; 32] = hasher.finalize().into();
|
||||
|
||||
let mut user_data = [0u8; 64];
|
||||
user_data[0..32].copy_from_slice(&digest);
|
||||
user_data
|
||||
}
|
||||
}
|
1
bisenzone-cw-mvp/packages/quartz-cw/src/msg/query.rs
Normal file
1
bisenzone-cw-mvp/packages/quartz-cw/src/msg/query.rs
Normal file
|
@ -0,0 +1 @@
|
|||
|
7
bisenzone-cw-mvp/packages/quartz-cw/src/prelude.rs
Normal file
7
bisenzone-cw-mvp/packages/quartz-cw/src/prelude.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
pub use crate::{
|
||||
handler::RawHandler,
|
||||
msg::{
|
||||
execute::RawExecute as QuartzExecuteMsg,
|
||||
instantiate::RawInstantiate as QuartzInstantiateMsg,
|
||||
},
|
||||
};
|
230
bisenzone-cw-mvp/packages/quartz-cw/src/state.rs
Normal file
230
bisenzone-cw-mvp/packages/quartz-cw/src/state.rs
Normal file
|
@ -0,0 +1,230 @@
|
|||
use core::time::Duration;
|
||||
|
||||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::{HexBinary, StdError};
|
||||
use cw_storage_plus::Item;
|
||||
use k256::ecdsa::VerifyingKey;
|
||||
|
||||
pub type MrEnclave = [u8; 32];
|
||||
pub type Nonce = [u8; 32];
|
||||
pub type UserData = [u8; 64];
|
||||
pub type Hash = [u8; 32];
|
||||
pub type Height = u64;
|
||||
pub type TrustThreshold = (u64, u64);
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Config {
|
||||
mr_enclave: MrEnclave,
|
||||
epoch_duration: Duration,
|
||||
light_client_opts: LightClientOpts,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new(
|
||||
mr_enclave: MrEnclave,
|
||||
epoch_duration: Duration,
|
||||
light_client_opts: LightClientOpts,
|
||||
) -> Self {
|
||||
Self {
|
||||
mr_enclave,
|
||||
epoch_duration,
|
||||
light_client_opts,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn light_client_opts(&self) -> &LightClientOpts {
|
||||
&self.light_client_opts
|
||||
}
|
||||
|
||||
pub fn mr_enclave(&self) -> MrEnclave {
|
||||
self.mr_enclave
|
||||
}
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct RawConfig {
|
||||
mr_enclave: HexBinary,
|
||||
epoch_duration: Duration,
|
||||
light_client_opts: RawLightClientOpts,
|
||||
}
|
||||
|
||||
impl RawConfig {
|
||||
pub fn mr_enclave(&self) -> &[u8] {
|
||||
self.mr_enclave.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<RawConfig> for Config {
|
||||
type Error = StdError;
|
||||
|
||||
fn try_from(value: RawConfig) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
mr_enclave: value.mr_enclave.to_array()?,
|
||||
epoch_duration: value.epoch_duration,
|
||||
light_client_opts: value
|
||||
.light_client_opts
|
||||
.try_into()
|
||||
.map_err(|e| StdError::parse_err("light_client_opts", e))?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Config> for RawConfig {
|
||||
fn from(value: Config) -> Self {
|
||||
Self {
|
||||
mr_enclave: value.mr_enclave.into(),
|
||||
epoch_duration: value.epoch_duration,
|
||||
light_client_opts: value.light_client_opts.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct LightClientOpts {
|
||||
chain_id: String,
|
||||
trusted_height: Height,
|
||||
trusted_hash: Hash,
|
||||
trust_threshold: TrustThreshold,
|
||||
trusting_period: u64,
|
||||
max_clock_drift: u64,
|
||||
max_block_lag: u64,
|
||||
}
|
||||
|
||||
impl LightClientOpts {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
chain_id: String,
|
||||
trusted_height: Height,
|
||||
trusted_hash: Hash,
|
||||
trust_threshold: TrustThreshold,
|
||||
trusting_period: u64,
|
||||
max_clock_drift: u64,
|
||||
max_block_lag: u64,
|
||||
) -> Result<Self, StdError> {
|
||||
let (numerator, denominator) = (trust_threshold.0, trust_threshold.1);
|
||||
if numerator > denominator {
|
||||
return Err(StdError::generic_err("trust_threshold_too_large"));
|
||||
}
|
||||
if denominator == 0 {
|
||||
return Err(StdError::generic_err("undefined_trust_threshold"));
|
||||
}
|
||||
if 3 * numerator < denominator {
|
||||
return Err(StdError::generic_err("trust_threshold_too_small"));
|
||||
}
|
||||
|
||||
let _trusted_height: i64 = trusted_height
|
||||
.try_into()
|
||||
.map_err(|_| StdError::generic_err("trusted_height too large"))?;
|
||||
|
||||
Ok(Self {
|
||||
chain_id,
|
||||
trusted_height,
|
||||
trusted_hash,
|
||||
trust_threshold,
|
||||
trusting_period,
|
||||
max_clock_drift,
|
||||
max_block_lag,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn chain_id(&self) -> &String {
|
||||
&self.chain_id
|
||||
}
|
||||
|
||||
pub fn trusted_height(&self) -> Height {
|
||||
self.trusted_height
|
||||
}
|
||||
|
||||
pub fn trusted_hash(&self) -> &Hash {
|
||||
&self.trusted_hash
|
||||
}
|
||||
|
||||
pub fn trust_threshold(&self) -> &TrustThreshold {
|
||||
&self.trust_threshold
|
||||
}
|
||||
|
||||
pub fn trusting_period(&self) -> u64 {
|
||||
self.trusting_period
|
||||
}
|
||||
|
||||
pub fn max_clock_drift(&self) -> u64 {
|
||||
self.max_clock_drift
|
||||
}
|
||||
|
||||
pub fn max_block_lag(&self) -> u64 {
|
||||
self.max_block_lag
|
||||
}
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct RawLightClientOpts {
|
||||
chain_id: String,
|
||||
trusted_height: u64,
|
||||
trusted_hash: HexBinary,
|
||||
trust_threshold: (u64, u64),
|
||||
trusting_period: u64,
|
||||
max_clock_drift: u64,
|
||||
max_block_lag: u64,
|
||||
}
|
||||
|
||||
impl TryFrom<RawLightClientOpts> for LightClientOpts {
|
||||
type Error = StdError;
|
||||
|
||||
fn try_from(value: RawLightClientOpts) -> Result<Self, Self::Error> {
|
||||
Self::new(
|
||||
value.chain_id,
|
||||
value.trusted_height,
|
||||
value.trusted_hash.to_array()?,
|
||||
(value.trust_threshold.0, value.trust_threshold.1),
|
||||
value.trusting_period,
|
||||
value.max_clock_drift,
|
||||
value.max_block_lag,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<LightClientOpts> for RawLightClientOpts {
|
||||
fn from(value: LightClientOpts) -> Self {
|
||||
Self {
|
||||
chain_id: value.chain_id,
|
||||
trusted_height: value.trusted_height,
|
||||
trusted_hash: Vec::<u8>::from(value.trusted_hash).into(),
|
||||
trust_threshold: (value.trust_threshold.0, value.trust_threshold.1),
|
||||
trusting_period: value.trusting_period,
|
||||
max_clock_drift: value.max_clock_drift,
|
||||
max_block_lag: value.max_block_lag,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct Session {
|
||||
nonce: HexBinary,
|
||||
pub_key: Option<HexBinary>,
|
||||
}
|
||||
|
||||
impl Session {
|
||||
pub fn create(nonce: Nonce) -> Self {
|
||||
Self {
|
||||
nonce: nonce.into(),
|
||||
pub_key: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_pub_key(mut self, nonce: Nonce, pub_key: VerifyingKey) -> Option<Self> {
|
||||
if self.nonce == nonce && self.pub_key.is_none() {
|
||||
self.pub_key = Some(pub_key.to_sec1_bytes().into_vec().into());
|
||||
Some(self)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nonce(&self) -> Nonce {
|
||||
self.nonce.to_array().expect("correct by construction")
|
||||
}
|
||||
}
|
||||
|
||||
pub const CONFIG: Item<'_, RawConfig> = Item::new("quartz_config");
|
||||
pub const SESSION: Item<'_, Session> = Item::new("quartz_session");
|
||||
pub const EPOCH_COUNTER: Item<'_, usize> = Item::new("epoch_counter");
|
25
bisenzone-cw-mvp/packages/quartz-tee-ra/Cargo.toml
Normal file
25
bisenzone-cw-mvp/packages/quartz-tee-ra/Cargo.toml
Normal file
|
@ -0,0 +1,25 @@
|
|||
[package]
|
||||
name = "quartz-tee-ra"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
cosmwasm-schema = "1.4.0"
|
||||
cosmwasm-std = "1.4.0"
|
||||
hex-literal = "0.4.1"
|
||||
num-bigint = "0.4.4"
|
||||
serde_json = "1.0.108"
|
||||
sha2 = "0.10.8"
|
||||
thiserror = { version = "1.0.49" }
|
||||
|
||||
der = { version = "0.7.9", default-features = false }
|
||||
displaydoc = { version = "0.2.4", default-features = false }
|
||||
mc-sgx-core-types = { git = "https://github.com/hu55a1n1/sgx" }
|
||||
mc-sgx-dcap-types = { git = "https://github.com/hu55a1n1/sgx" }
|
||||
mc-sgx-dcap-sys-types = { git = "https://github.com/hu55a1n1/sgx" }
|
||||
mc-attestation-verifier = { git = "https://github.com/hu55a1n1/attestation" }
|
||||
serde = { version = "1.0.198", default-features = false }
|
||||
x509-cert = { version = "0.2.5", default-features = false }
|
||||
zeroize = { version = "1.7.0", default-features = false }
|
|
@ -0,0 +1,16 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw
|
||||
aDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv
|
||||
cnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ
|
||||
BgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG
|
||||
A1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0
|
||||
aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT
|
||||
AlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7
|
||||
1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB
|
||||
uzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ
|
||||
MEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50
|
||||
ZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV
|
||||
Ur9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI
|
||||
KoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg
|
||||
AiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=
|
||||
-----END CERTIFICATE-----
|
14
bisenzone-cw-mvp/packages/quartz-tee-ra/src/intel_sgx.rs
Normal file
14
bisenzone-cw-mvp/packages/quartz-tee-ra/src/intel_sgx.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
use thiserror::Error;
|
||||
|
||||
pub mod dcap;
|
||||
pub mod epid;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("Specified user data does not match the report")]
|
||||
UserDataMismatch,
|
||||
#[error("Specified MRENCLAVE does not match the report")]
|
||||
MrEnclaveMismatch,
|
||||
#[error("EPID specific error: {0}")]
|
||||
Epid(#[from] epid::Error),
|
||||
}
|
130
bisenzone-cw-mvp/packages/quartz-tee-ra/src/intel_sgx/dcap.rs
Normal file
130
bisenzone-cw-mvp/packages/quartz-tee-ra/src/intel_sgx/dcap.rs
Normal file
|
@ -0,0 +1,130 @@
|
|||
pub mod certificate_chain;
|
||||
pub mod mc_attest_verifier;
|
||||
pub mod mc_attest_verifier_types;
|
||||
|
||||
/// Root anchor PEM file for use with DCAP
|
||||
pub const DCAP_ROOT_ANCHOR: &str = include_str!("../../data/DcapRootCACert.pem");
|
||||
|
||||
pub use mc_attest_verifier::dcap::DcapVerifier;
|
||||
pub use mc_attest_verifier_types::verification::EnclaveReportDataContents;
|
||||
pub use mc_attestation_verifier::*;
|
||||
pub use mc_sgx_dcap_sys_types::sgx_ql_qve_collateral_t;
|
||||
pub use mc_sgx_dcap_types::{CertificationData, Collateral};
|
||||
pub use x509_cert::Certificate;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use hex_literal::hex;
|
||||
use mc_sgx_dcap_types::Quote3;
|
||||
|
||||
#[test]
|
||||
fn test_quote_parse() {
|
||||
let quote_bytes = hex!(
|
||||
"03000200000000000a000f00939a7233f79c4ca9940a0db3957f0607ce4\
|
||||
8836fd48a951172fe155220a719bd00000000141402070180010000000000000000000000000000000000000000\
|
||||
00000000000000000000000000000000000000000005000000000000000700000000000000dc43f8c42d8e5f52c\
|
||||
8bbd68f426242153f0be10630ff8cca255129a3ca03d27300000000000000000000000000000000000000000000\
|
||||
000000000000000000001cf2e52911410fbf3f199056a98d58795a559a2e800933f7fcd13d048462271c0000000\
|
||||
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
|
||||
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
|
||||
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
|
||||
00000000000000000000000000000000000000009113b0be77ed5d0d68680ec77206b8d587ed40679b71321ccdd\
|
||||
5405e4d54a682000000000000000000000000000000000000000000000000000000000000000044100000552c9b\
|
||||
321744cf259b8c239213413ca4226ea8a705ad6eabb505bb4f3a8850f1ed9f2ff3d9e17ba8be8cc69a0d911575a\
|
||||
813392202bddaa7b971d406704989e0be6177e039634cfbca4739ac246fda7df8c312a98f30f57b63f3c8921fce\
|
||||
51d90a93031f97f769637be9b028e7b007a4e458d4fa717befbd81b069050825801314140207018001000000000\
|
||||
0000000000000000000000000000000000000000000000000000000000000000000000000150000000000000007\
|
||||
0000000000000096b347a64e5a045e27369c26e6dcda51fd7c850e9b3a3a79e718f43261dee1e40000000000000\
|
||||
0000000000000000000000000000000000000000000000000008c4f5775d796503e96137f77c68a829a0056ac8d\
|
||||
ed70140b081b094490c57bff0000000000000000000000000000000000000000000000000000000000000000000\
|
||||
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
|
||||
000000000000000000000000000000000001000a000000000000000000000000000000000000000000000000000\
|
||||
00000000000000000000000000000000000000000000000000000000000000000000000b0f056c5355f6c770413\
|
||||
938c2a41ed1b5c34ecb35f85fa539f16cca7a30d6da900000000000000000000000000000000000000000000000\
|
||||
00000000000000000010a4d552582e428f8fd138cbb5f8af51050776f2c487996147d4ebfb5c817ba733905f30a\
|
||||
f7b4f340eaf0fdf2bb64dcb045d56f1609a1b042e6f5aeed09175c2000000102030405060708090a0b0c0d0e0f1\
|
||||
01112131415161718191a1b1c1d1e1f0500dc0d00002d2d2d2d2d424547494e2043455254494649434154452d2d\
|
||||
2d2d2d0a4d4949456a544343424453674177494241674956414a5172493559365a78484836785034424941715a4\
|
||||
e6b326e4c7a594d416f4743437147534d343942414d430a4d484578497a416842674e5642414d4d476b6c756447\
|
||||
567349464e48574342515130736755484a765932567a6332397949454e424d526f77474159445651514b0a44424\
|
||||
64a626e526c6243424462334a7762334a6864476c76626a45554d424947413155454277774c5532467564474567\
|
||||
51327868636d4578437a414a42674e560a4241674d416b4e424d517377435159445651514745774a56557a41654\
|
||||
67730794d7a45784d5441784e7a45334d4452614677307a4d4445784d5441784e7a45330a4d4452614d48417849\
|
||||
6a416742674e5642414d4d47556c756447567349464e4857434251513073675132567964476c6d61574e6864475\
|
||||
578476a415942674e560a42416f4d45556c756447567349454e76636e4276636d4630615739754d525177456759\
|
||||
4456515148444174545957353059534244624746795954454c4d416b470a413155454341774351304578437a414\
|
||||
a42674e5642415954416c56544d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a30444151634451\
|
||||
6741450a77625468574d583134443163657835317875614958456771517a69636e744b7a48454a32536f31336e3\
|
||||
84a427050314a67383673764263462f7070715a554e710a68524b4642667469584c6d4f536c614955784e6e5136\
|
||||
4f434171677767674b6b4d42384741315564497751594d426141464e446f71747031312f6b75535265590a50487\
|
||||
3555a644456386c6c4e4d477747413155644877526c4d474d77596142666f463247573268306448427a4f693876\
|
||||
595842704c6e527964584e305a57527a0a5a584a3261574e6c63793570626e526c6243356a62323076633264344\
|
||||
c324e6c636e52705a6d6c6a5958527062323476646a517663474e7259334a7350324e680a5058427962324e6c63\
|
||||
334e7663695a6c626d4e765a476c755a7a316b5a584977485159445652304f42425945464a57566e41395a63736\
|
||||
f3753356b6a2f647a4a0a594f3034534175644d41344741315564447745422f775145417749477744414d42674e\
|
||||
5648524d4241663845416a41414d4949423141594a4b6f5a496876684e0a4151304242494942785443434163457\
|
||||
74867594b4b6f5a496876684e41513042415151514d6d5867725757774c59554164456d6c766c36615344434341\
|
||||
5751470a43697147534962345451454e41514977676746554d42414743797147534962345451454e41514942416\
|
||||
745554d42414743797147534962345451454e415149430a416745554d42414743797147534962345451454e4151\
|
||||
4944416745434d42414743797147534962345451454e41514945416745454d42414743797147534962340a54514\
|
||||
54e41514946416745424d42454743797147534962345451454e41514947416749416744415142677371686b6947\
|
||||
2b4530424451454342774942414441510a42677371686b69472b453042445145434341494241444151426773716\
|
||||
86b69472b45304244514543435149424144415142677371686b69472b453042445145430a436749424144415142\
|
||||
677371686b69472b45304244514543437749424144415142677371686b69472b453042445145434441494241444\
|
||||
15142677371686b69470a2b45304244514543445149424144415142677371686b69472b45304244514543446749\
|
||||
424144415142677371686b69472b4530424451454344774942414441510a42677371686b69472b4530424451454\
|
||||
3454149424144415142677371686b69472b45304244514543455149424454416642677371686b69472b45304244\
|
||||
5145430a4567515146425143424147414141414141414141414141414144415142676f71686b69472b453042445\
|
||||
14544424149414144415542676f71686b69472b4530420a44514545424159416b473668414141774477594b4b6f\
|
||||
5a496876684e4151304242516f424144414b42676771686b6a4f5051514441674e4841444245416942560a6e584\
|
||||
667364277466a6945474230417162424e702b4b56734a477245744f4f49666e6f365450387031414967536c4430\
|
||||
574e39595261575968346534656835330a314637434537664964724f55414c5177757632735948513d0a2d2d2d2\
|
||||
d2d454e442043455254494649434154452d2d2d2d2d0a2d2d2d2d2d424547494e2043455254494649434154452d\
|
||||
2d2d2d2d0a4d4949436d444343416a36674177494241674956414e446f71747031312f6b7553526559504873555\
|
||||
a644456386c6c4e4d416f4743437147534d343942414d430a4d476778476a415942674e5642414d4d45556c7564\
|
||||
47567349464e48574342536232393049454e424d526f77474159445651514b4442464a626e526c624342440a623\
|
||||
34a7762334a6864476c76626a45554d424947413155454277774c553246756447456751327868636d4578437a41\
|
||||
4a42674e564241674d416b4e424d5173770a435159445651514745774a56557a4165467730784f4441314d6a457\
|
||||
84d4455774d5442614677307a4d7a41314d6a45784d4455774d5442614d484578497a41680a42674e5642414d4d\
|
||||
476b6c756447567349464e48574342515130736755484a765932567a6332397949454e424d526f7747415944565\
|
||||
1514b4442464a626e526c0a6243424462334a7762334a6864476c76626a45554d424947413155454277774c5532\
|
||||
46756447456751327868636d4578437a414a42674e564241674d416b4e420a4d517377435159445651514745774\
|
||||
a56557a425a4d424d4742797147534d34394167454743437147534d34394177454841304941424c39712b4e4d70\
|
||||
32494f670a74646c31626b2f75575a352b5447516d38614369387a373866732b664b435133642b75447a586e565\
|
||||
44154325a68444369667949754a77764e33774e427039690a484253534d4a4d4a72424f6a676273776762677748\
|
||||
7759445652306a42426777466f4155496d554d316c71644e496e7a6737535655723951477a6b6e427177770a556\
|
||||
759445652306642457377535442486f45576751345a426148523063484d364c79396a5a584a3061575a70593246\
|
||||
305a584d7564484a316333526c5a484e6c0a636e5a705932567a4c6d6c75644756734c6d4e766253394a626e526\
|
||||
c62464e4857464a76623352445153356b5a584977485159445652304f42425945464e446f0a71747031312f6b75\
|
||||
53526559504873555a644456386c6c4e4d41344741315564447745422f77514541774942426a415342674e56485\
|
||||
24d4241663845434441470a4151482f416745414d416f4743437147534d343942414d43413067414d4555434951\
|
||||
434a6754627456714f795a316d336a716941584d365159613672357357530a34792f4737793875494a477864774\
|
||||
9675271507642534b7a7a516167424c517135733541373070646f6961524a387a2f3075447a344e675639316b3d\
|
||||
0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a2d2d2d2d2d424547494e20434552544946494\
|
||||
34154452d2d2d2d2d0a4d4949436a7a4343416a53674177494241674955496d554d316c71644e496e7a67375356\
|
||||
55723951477a6b6e42717777436759494b6f5a497a6a3045417749770a614445614d42674741315545417777525\
|
||||
35735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c75644756734945\
|
||||
4e760a636e4276636d4630615739754d52517745675944565151484441745459573530595342446247467959544\
|
||||
54c4d416b47413155454341774351304578437a414a0a42674e5642415954416c56544d423458445445344d4455\
|
||||
794d5445774e4455784d466f58445451354d54497a4d54497a4e546b314f566f77614445614d4267470a4131554\
|
||||
541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c7564\
|
||||
47567349454e76636e4276636d46300a615739754d5251774567594456515148444174545957353059534244624\
|
||||
746795954454c4d416b47413155454341774351304578437a414a42674e56424159540a416c56544d466b774577\
|
||||
59484b6f5a497a6a3043415159494b6f5a497a6a3044415163445167414543366e45774d4449595a4f6a2f69505\
|
||||
773437a61454b69370a314f694f534c52466857476a626e42564a66566e6b59347533496a6b4459594c304d784f\
|
||||
346d717379596a6c42616c54565978465032734a424b357a6c4b4f420a757a43427544416642674e5648534d454\
|
||||
7444157674251695a517a575770303069664f44744a5653763141624f5363477244425342674e5648523845537a\
|
||||
424a0a4d45656752614244686b466f64485277637a6f764c324e6c636e52705a6d6c6a5958526c63793530636e5\
|
||||
67a6447566b63325679646d6c6a5a584d75615735300a5a577775593239744c306c756447567355306459556d39\
|
||||
7664454e424c6d526c636a416442674e564851344546675155496d554d316c71644e496e7a673753560a5572395\
|
||||
1477a6b6e4271777744675944565230504151482f42415144416745474d42494741315564457745422f7751494d\
|
||||
4159424166384341514577436759490a4b6f5a497a6a3045417749445351417752674968414f572f35516b522b5\
|
||||
33943695344634e6f6f774c7550524c735747662f59693747535839344267775477670a41694541344a306c7248\
|
||||
6f4d732b586f356f2f7358364f39515778485241765a55474f6452513763767152586171493d0a2d2d2d2d2d454\
|
||||
e442043455254494649434154452d2d2d2d2d0a00"
|
||||
);
|
||||
let _quote: Quote3<Vec<u8>> = Quote3::try_from(quote_bytes.to_vec())
|
||||
.expect("Failed to parse quote")
|
||||
.into();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
use der::DateTime;
|
||||
use mc_attestation_verifier::{CertificateChainVerifier, CertificateChainVerifierError};
|
||||
use x509_cert::{crl::CertificateList, Certificate};
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq)]
|
||||
pub struct TlsCertificateChainVerifier;
|
||||
|
||||
impl CertificateChainVerifier for TlsCertificateChainVerifier {
|
||||
fn verify_certificate_chain<'a, 'b>(
|
||||
&self,
|
||||
_certificate_chain: impl IntoIterator<Item = &'a Certificate>,
|
||||
_crls: impl IntoIterator<Item = &'b CertificateList>,
|
||||
_time: impl Into<Option<DateTime>>,
|
||||
) -> Result<(), CertificateChainVerifierError> {
|
||||
todo!()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
// Trimmed down version of the `mc_attest_verifier` crate (for DCAP verification only) ->
|
||||
// https://github.com/hu55a1n1/mobilecoin/blob/a1eba594f5b1ebe3d2b0736cf76d38120f84a4a0/attest/verifier
|
||||
|
||||
pub mod dcap;
|
|
@ -0,0 +1,82 @@
|
|||
// Copyright (c) 2023 The MobileCoin Foundation
|
||||
|
||||
//! Verify the contents of a Quote3.
|
||||
|
||||
use der::DateTime;
|
||||
use mc_attestation_verifier::{
|
||||
Accessor, And, AndOutput, Evidence, EvidenceValue, EvidenceVerifier, ReportDataVerifier,
|
||||
TrustedIdentity, VerificationOutput, Verifier,
|
||||
};
|
||||
use mc_sgx_core_types::ReportData;
|
||||
|
||||
// use super::DCAP_ROOT_ANCHOR;
|
||||
use super::super::certificate_chain::TlsCertificateChainVerifier;
|
||||
use super::super::mc_attest_verifier_types::verification::EnclaveReportDataContents;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DcapVerifier {
|
||||
verifier: And<EvidenceVerifier<TlsCertificateChainVerifier>, ReportDataHashVerifier>,
|
||||
}
|
||||
|
||||
type DcapVerifierOutput = AndOutput<EvidenceValue, ReportData>;
|
||||
|
||||
impl DcapVerifier {
|
||||
/// Create a new instance of the DcapVerifier.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `trusted_identities` - The allowed identities that can be used in an
|
||||
/// enclave. Verification will succeed if any of these match.
|
||||
/// * `time` - The time to use to verify the validity of the certificates
|
||||
/// and collateral. If time is provided, verification will fail if this
|
||||
/// time is before or after any of the validity periods. Otherwise, time
|
||||
/// validation of certificates will be skipped.
|
||||
pub fn new<I, ID>(
|
||||
trusted_identities: I,
|
||||
time: impl Into<Option<DateTime>>,
|
||||
report_data: EnclaveReportDataContents,
|
||||
) -> Self
|
||||
where
|
||||
I: IntoIterator<Item = ID>,
|
||||
ID: Into<TrustedIdentity>,
|
||||
{
|
||||
let certificate_verifier = TlsCertificateChainVerifier;
|
||||
let verifier = And::new(
|
||||
EvidenceVerifier::new(certificate_verifier, trusted_identities, time),
|
||||
ReportDataHashVerifier::new(report_data),
|
||||
);
|
||||
Self { verifier }
|
||||
}
|
||||
|
||||
/// Verify the `evidence`
|
||||
pub fn verify(&self, evidence: &Evidence<Vec<u8>>) -> VerificationOutput<DcapVerifierOutput> {
|
||||
self.verifier.verify(evidence)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ReportDataHashVerifier {
|
||||
report_data_verifier: ReportDataVerifier,
|
||||
}
|
||||
|
||||
impl ReportDataHashVerifier {
|
||||
pub fn new(report_data: EnclaveReportDataContents) -> Self {
|
||||
let mut expected_report_data_bytes = [0u8; 64];
|
||||
expected_report_data_bytes[..32].copy_from_slice(report_data.sha256().as_ref());
|
||||
let mut mask = [0u8; 64];
|
||||
mask[..32].copy_from_slice([0xffu8; 32].as_ref());
|
||||
let report_data_verifier =
|
||||
ReportDataVerifier::new(expected_report_data_bytes.into(), mask.into());
|
||||
|
||||
Self {
|
||||
report_data_verifier,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Accessor<ReportData>> Verifier<E> for ReportDataHashVerifier {
|
||||
type Value = ReportData;
|
||||
|
||||
fn verify(&self, evidence: &E) -> VerificationOutput<Self::Value> {
|
||||
self.report_data_verifier.verify(evidence)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
// Heavily trimmed down version of the `mc-attest-verifier-types` crate
|
||||
// https://github.com/hu55a1n1/mobilecoin/blob/89d90c427bf9cf637a124c0afad266d52b573dc8/attest/verifier/types/src/verification.rs
|
||||
|
||||
pub mod verification;
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright (c) 2018-2022 The MobileCoin Foundation
|
||||
|
||||
//! Attestation Verification Report type.
|
||||
|
||||
use core::fmt::Debug;
|
||||
|
||||
use mc_sgx_core_types::QuoteNonce;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
/// Structure for holding the contents of the Enclave's Report Data.
|
||||
/// The Enclave Quote's ReportData member contains a SHA256 hash of this
|
||||
/// structure's contents.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
||||
pub struct EnclaveReportDataContents {
|
||||
nonce: QuoteNonce,
|
||||
custom_identity: Option<[u8; 32]>,
|
||||
}
|
||||
|
||||
impl EnclaveReportDataContents {
|
||||
/// Create a new EnclaveReportDataContents.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `nonce` - The nonce provided from the enclave when generating the
|
||||
/// Report.
|
||||
/// * `key` - The public key of the enclave. Previously this was bytes 0..32
|
||||
/// of the enclave's [`ReportData`](mc-sgx-core-types::ReportData).
|
||||
/// * `custom_identity` - The custom identity of the enclave. Previously
|
||||
/// this was bytes 32..64 of the enclave's
|
||||
/// [`ReportData`](mc-sgx-core-types::ReportData).
|
||||
pub fn new(nonce: QuoteNonce, custom_identity: impl Into<Option<[u8; 32]>>) -> Self {
|
||||
Self {
|
||||
nonce,
|
||||
custom_identity: custom_identity.into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the nonce
|
||||
pub fn nonce(&self) -> &QuoteNonce {
|
||||
&self.nonce
|
||||
}
|
||||
|
||||
/// Get the custom identity
|
||||
pub fn custom_identity(&self) -> Option<&[u8; 32]> {
|
||||
self.custom_identity.as_ref()
|
||||
}
|
||||
|
||||
/// Returns a SHA256 hash of the contents of this structure.
|
||||
///
|
||||
/// This is the value that is stored in bytes 0..32 of the enclave's
|
||||
/// [`ReportData`](mc-sgx-core-types::ReportData).
|
||||
pub fn sha256(&self) -> [u8; 32] {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(&self.nonce);
|
||||
if let Some(custom_identity) = &self.custom_identity {
|
||||
hasher.update(custom_identity);
|
||||
}
|
||||
hasher.finalize().into()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
use hex_literal::hex;
|
||||
use thiserror::Error;
|
||||
|
||||
pub const INTEL_ROOT_MODULUS: &[u8] = &hex!("a97a2de0e66ea6147c9ee745ac0162686c7192099afc4b3f040fad6de093511d74e802f510d716038157dcaf84f4104bd3fed7e6b8f99c8817fd1ff5b9b864296c3d81fa8f1b729e02d21d72ffee4ced725efe74bea68fbc4d4244286fcdd4bf64406a439a15bcb4cf67754489c423972b4a80df5c2e7c5bc2dbaf2d42bb7b244f7c95bf92c75d3b33fc5410678a89589d1083da3acc459f2704cd99598c275e7c1878e00757e5bdb4e840226c11c0a17ff79c80b15c1ddb5af21cc2417061fbd2a2da819ed3b72b7efaa3bfebe2805c9b8ac19aa346512d484cfc81941e15f55881cc127e8f7aa12300cd5afb5742fa1d20cb467a5beb1c666cf76a368978b5");
|
||||
|
||||
pub const INTEL_ROOT_EXPONENT: &[u8] =
|
||||
&hex!("0000000000000000000000000000000000000000000000000000000000010001");
|
||||
|
||||
pub mod types;
|
||||
|
||||
pub mod verifier;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("Recovered digest from signature does not match the specified report")]
|
||||
RecoveredDigestMismatch,
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::Binary;
|
||||
|
||||
#[cw_serde]
|
||||
pub struct IASReport {
|
||||
pub report: ReportBody,
|
||||
#[serde(rename = "reportsig")]
|
||||
pub report_sig: Binary,
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct ReportBody {
|
||||
pub id: String,
|
||||
pub timestamp: String,
|
||||
pub version: u64,
|
||||
#[serde(rename = "epidPseudonym")]
|
||||
pub epid_pseudonym: Binary,
|
||||
#[serde(rename = "advisoryURL")]
|
||||
pub advisory_url: String,
|
||||
#[serde(rename = "advisoryIDs")]
|
||||
pub advisory_ids: Vec<String>,
|
||||
#[serde(rename = "isvEnclaveQuoteStatus")]
|
||||
pub isv_enclave_quote_status: String,
|
||||
#[serde(rename = "platformInfoBlob")]
|
||||
pub platform_info_blob: String,
|
||||
#[serde(rename = "isvEnclaveQuoteBody")]
|
||||
pub isv_enclave_quote_body: IsvEnclaveQuoteBody,
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
#[serde(transparent)]
|
||||
pub struct IsvEnclaveQuoteBody(Binary);
|
||||
|
||||
impl IsvEnclaveQuoteBody {
|
||||
pub fn mrenclave(&self) -> [u8; 32] {
|
||||
Self::array_chunk(self.0.as_slice(), 112)
|
||||
}
|
||||
|
||||
pub fn user_data(&self) -> [u8; 64] {
|
||||
Self::array_chunk(self.0.as_slice(), 368)
|
||||
}
|
||||
|
||||
fn array_chunk<const N: usize>(quote_body: &[u8], offset: usize) -> [u8; N] {
|
||||
assert!(offset + N <= quote_body.len());
|
||||
quote_body[offset..offset + N]
|
||||
.try_into()
|
||||
.expect("array length mismatch")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
use cosmwasm_std::ensure_eq;
|
||||
use num_bigint::BigUint;
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
use crate::intel_sgx::{
|
||||
epid::{types::IASReport, Error as EpidError, INTEL_ROOT_EXPONENT, INTEL_ROOT_MODULUS},
|
||||
Error,
|
||||
};
|
||||
|
||||
/// Given an RSA signature and the signer's exponent + modulus we recover the digest that was signed by the signature.
|
||||
pub fn recover_signature_digest(signature: &[u8], exponent: &[u8], modulus: &[u8]) -> Vec<u8> {
|
||||
let sig_as_bignum_be = BigUint::from_bytes_be(signature);
|
||||
let intel_modulus_be = BigUint::from_bytes_be(modulus);
|
||||
let intel_exponent_be = BigUint::from_bytes_be(exponent);
|
||||
|
||||
let digest_be = sig_as_bignum_be.modpow(&intel_exponent_be, &intel_modulus_be);
|
||||
|
||||
// last 32 bytes contain the digest
|
||||
let digest_bytes = digest_be.to_bytes_be();
|
||||
let n = digest_bytes.len();
|
||||
digest_bytes[n - 32..n].to_vec()
|
||||
}
|
||||
|
||||
pub fn verify(
|
||||
ias_report: IASReport,
|
||||
mrenclave: impl AsRef<[u8]>,
|
||||
user_data: impl AsRef<[u8]>,
|
||||
) -> Result<(), Error> {
|
||||
// Extract the payload from the quote body
|
||||
let user_data_in_quote = ias_report.report.isv_enclave_quote_body.user_data();
|
||||
|
||||
// check user_report_data
|
||||
ensure_eq!(
|
||||
user_data_in_quote,
|
||||
user_data.as_ref(),
|
||||
Error::UserDataMismatch
|
||||
);
|
||||
|
||||
// Extract the mrenclave from the quote body
|
||||
let mrenclave_in_quote = ias_report.report.isv_enclave_quote_body.mrenclave();
|
||||
|
||||
// check mrenclave
|
||||
ensure_eq!(
|
||||
mrenclave_in_quote,
|
||||
mrenclave.as_ref(),
|
||||
Error::MrEnclaveMismatch
|
||||
);
|
||||
|
||||
// Recover the RSA signature's digest
|
||||
let recovered_digest = recover_signature_digest(
|
||||
ias_report.report_sig.as_slice(),
|
||||
INTEL_ROOT_EXPONENT,
|
||||
INTEL_ROOT_MODULUS,
|
||||
);
|
||||
// Convert the recovered digest into a byte slice
|
||||
let recovered_digest = recovered_digest.as_slice();
|
||||
|
||||
// Convert the ias report as a json string, removing all the backslashes to escape stuff
|
||||
let ias_report_asjson = serde_json::to_string(&ias_report.report)
|
||||
.expect("infallible serializer for IASReport")
|
||||
.replace('\\', "");
|
||||
// Convert the ias report without the back slashes to bytes
|
||||
let ias_report_asbytes = ias_report_asjson.as_bytes();
|
||||
// We are going to calculate our own digest of the ias report
|
||||
let mut hasher = Sha256::default();
|
||||
// Update the hasher contents with that of the ias report json
|
||||
hasher.update(ias_report_asbytes);
|
||||
// finalize the sha256 hasher so that it produces a byte slice of the digest, should be 32 bytes
|
||||
let ias_report_digest = &hasher.finalize()[..];
|
||||
|
||||
// ensure that the recovered digest from the signature matches the digest of the report
|
||||
ensure_eq!(
|
||||
ias_report_digest,
|
||||
recovered_digest,
|
||||
EpidError::RecoveredDigestMismatch
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::HexBinary;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[cw_serde]
|
||||
pub enum QueryMsg {
|
||||
/// Verify an attestation
|
||||
VerifyEpidAttestation {
|
||||
// The report that is generated by an enclave
|
||||
report: IASReport,
|
||||
// The MRENCLAVE of this enclave (as hex string)
|
||||
mrenclave: HexBinary,
|
||||
// User data - whose commitment is in the `user_report_data` (as hex string)
|
||||
user_data: HexBinary,
|
||||
},
|
||||
}
|
||||
|
||||
fn parse_attestation(query_verifier: &str) -> (IASReport, HexBinary, HexBinary) {
|
||||
let query_verifier: QueryMsg =
|
||||
serde_json::from_str(query_verifier).expect("deserialize query");
|
||||
match query_verifier {
|
||||
QueryMsg::VerifyEpidAttestation {
|
||||
report,
|
||||
mrenclave,
|
||||
user_data,
|
||||
} => (report, mrenclave, user_data),
|
||||
}
|
||||
}
|
||||
|
||||
fn verify_attestation(query_verifier: &str) {
|
||||
let (report, mrenclave, user_data) = parse_attestation(query_verifier);
|
||||
verify(report, mrenclave, user_data).expect("RA verification failure");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_verifier_ok() {
|
||||
verify_attestation(
|
||||
r#"{
|
||||
"verify_epid_attestation": {
|
||||
"report": {"report":{"id":"5246688123689513540899231107533660789","timestamp":"2024-02-07T17:06:23.913745","version":4,"epidPseudonym":"+CUyIi74LPqS6M0NF7YrSxLqPdX3MKs6D6LIPqRG/ZEB4WmxZVvxAJwdwg/0m9cYnUUQguLnJotthX645lAogfJgO8Xg5/91lSegwyUKvHmKgtjOHX/YTbVe/wmgWiBdaL+KmarY0Je459Px/FqGLWLsAF7egPAJRd1Xn88Znrs=","advisoryURL":"https://security-center.intel.com","advisoryIDs":["INTEL-SA-00161","INTEL-SA-00219","INTEL-SA-00289","INTEL-SA-00334","INTEL-SA-00615"],"isvEnclaveQuoteStatus":"CONFIGURATION_AND_SW_HARDENING_NEEDED","platformInfoBlob":"150200650000080000141402040180070000000000000000000D00000C000000020000000000000CB0F08115F3DE71AE97980FE5E10B042054930ACE356C79EC44603D3F890756EC6ED73927A7C58CDE9AF1E754AEC77E335E8D80294407936BEB6404F27669FF7BB1","isvEnclaveQuoteBody":"AgABALAMAAAPAA8AAAAAAFHK9aSLRQ1iSu/jKG0xSJQAAAAAAAAAAAAAAAAAAAAAFBQCBwGAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAHAAAAAAAAAOPC8qW4QNieBprK/8rbZRDvhmpz06nuVxAO1fhkbuS7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc8uUpEUEPvz8ZkFapjVh5WlWaLoAJM/f80T0EhGInHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRE7C+d+1dDWhoDsdyBrjVh+1AZ5txMhzN1UBeTVSmggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},"reportsig":"YcY4SPvkfR4P2E8A5huutCeS+vY/ir+xq6disalNfNtAcUyOIOqTPVXhAZgY1M5B47Hjj1oYWf2qC2w+dnj7VcZjzO9oR0pJYdA+A7jaVrNzH2eXA79yICkuU8WE/x58I0j5vjXLoHXahaKlpZkMeTphqBY8u+FTVSdP3cWPho4viPapTfQRuEWmYq4KIq2zSr6wLg3Pz+yQ+G3e9BASVkLYxdYGTDFH1pMmfas9SEI7V4I+j8DaXmL8bucSRakmcQdmDMPGiA7mvIhSAlprzCrdxM7CHeUC6MPLN1fmFFcc9kyO/ved69j/651MWC83GgxSJ15L80U+DQzmrSW8xg=="},
|
||||
"mrenclave": "e3c2f2a5b840d89e069acaffcadb6510ef866a73d3a9ee57100ed5f8646ee4bb",
|
||||
"user_data": "9113b0be77ed5d0d68680ec77206b8d587ed40679b71321ccdd5405e4d54a6820000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
}"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_verifier_bad_mrenclave() {
|
||||
verify_attestation(
|
||||
r#"{
|
||||
"verify_epid_attestation": {
|
||||
"report": {"report":{"id":"5246688123689513540899231107533660789","timestamp":"2024-02-07T17:06:23.913745","version":4,"epidPseudonym":"+CUyIi74LPqS6M0NF7YrSxLqPdX3MKs6D6LIPqRG/ZEB4WmxZVvxAJwdwg/0m9cYnUUQguLnJotthX645lAogfJgO8Xg5/91lSegwyUKvHmKgtjOHX/YTbVe/wmgWiBdaL+KmarY0Je459Px/FqGLWLsAF7egPAJRd1Xn88Znrs=","advisoryURL":"https://security-center.intel.com","advisoryIDs":["INTEL-SA-00161","INTEL-SA-00219","INTEL-SA-00289","INTEL-SA-00334","INTEL-SA-00615"],"isvEnclaveQuoteStatus":"CONFIGURATION_AND_SW_HARDENING_NEEDED","platformInfoBlob":"150200650000080000141402040180070000000000000000000D00000C000000020000000000000CB0F08115F3DE71AE97980FE5E10B042054930ACE356C79EC44603D3F890756EC6ED73927A7C58CDE9AF1E754AEC77E335E8D80294407936BEB6404F27669FF7BB1","isvEnclaveQuoteBody":"AgABALAMAAAPAA8AAAAAAFHK9aSLRQ1iSu/jKG0xSJQAAAAAAAAAAAAAAAAAAAAAFBQCBwGAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAHAAAAAAAAAOPC8qW4QNieBprK/8rbZRDvhmpz06nuVxAO1fhkbuS7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc8uUpEUEPvz8ZkFapjVh5WlWaLoAJM/f80T0EhGInHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRE7C+d+1dDWhoDsdyBrjVh+1AZ5txMhzN1UBeTVSmggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},"reportsig":"YcY4SPvkfR4P2E8A5huutCeS+vY/ir+xq6disalNfNtAcUyOIOqTPVXhAZgY1M5B47Hjj1oYWf2qC2w+dnj7VcZjzO9oR0pJYdA+A7jaVrNzH2eXA79yICkuU8WE/x58I0j5vjXLoHXahaKlpZkMeTphqBY8u+FTVSdP3cWPho4viPapTfQRuEWmYq4KIq2zSr6wLg3Pz+yQ+G3e9BASVkLYxdYGTDFH1pMmfas9SEI7V4I+j8DaXmL8bucSRakmcQdmDMPGiA7mvIhSAlprzCrdxM7CHeUC6MPLN1fmFFcc9kyO/ved69j/651MWC83GgxSJ15L80U+DQzmrSW8xg=="},
|
||||
"mrenclave": "f3c2f2a5b840d89e069acaffcadb6510ef866a73d3a9ee57100ed5f8646ee4bb",
|
||||
"user_data": "9113b0be77ed5d0d68680ec77206b8d587ed40679b71321ccdd5405e4d54a6820000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
}"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_verifier_bad_user_data() {
|
||||
verify_attestation(
|
||||
r#"{
|
||||
"verify_epid_attestation": {
|
||||
"report": {"report":{"id":"5246688123689513540899231107533660789","timestamp":"2024-02-07T17:06:23.913745","version":4,"epidPseudonym":"+CUyIi74LPqS6M0NF7YrSxLqPdX3MKs6D6LIPqRG/ZEB4WmxZVvxAJwdwg/0m9cYnUUQguLnJotthX645lAogfJgO8Xg5/91lSegwyUKvHmKgtjOHX/YTbVe/wmgWiBdaL+KmarY0Je459Px/FqGLWLsAF7egPAJRd1Xn88Znrs=","advisoryURL":"https://security-center.intel.com","advisoryIDs":["INTEL-SA-00161","INTEL-SA-00219","INTEL-SA-00289","INTEL-SA-00334","INTEL-SA-00615"],"isvEnclaveQuoteStatus":"CONFIGURATION_AND_SW_HARDENING_NEEDED","platformInfoBlob":"150200650000080000141402040180070000000000000000000D00000C000000020000000000000CB0F08115F3DE71AE97980FE5E10B042054930ACE356C79EC44603D3F890756EC6ED73927A7C58CDE9AF1E754AEC77E335E8D80294407936BEB6404F27669FF7BB1","isvEnclaveQuoteBody":"AgABALAMAAAPAA8AAAAAAFHK9aSLRQ1iSu/jKG0xSJQAAAAAAAAAAAAAAAAAAAAAFBQCBwGAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAHAAAAAAAAAOPC8qW4QNieBprK/8rbZRDvhmpz06nuVxAO1fhkbuS7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc8uUpEUEPvz8ZkFapjVh5WlWaLoAJM/f80T0EhGInHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRE7C+d+1dDWhoDsdyBrjVh+1AZ5txMhzN1UBeTVSmggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},"reportsig":"YcY4SPvkfR4P2E8A5huutCeS+vY/ir+xq6disalNfNtAcUyOIOqTPVXhAZgY1M5B47Hjj1oYWf2qC2w+dnj7VcZjzO9oR0pJYdA+A7jaVrNzH2eXA79yICkuU8WE/x58I0j5vjXLoHXahaKlpZkMeTphqBY8u+FTVSdP3cWPho4viPapTfQRuEWmYq4KIq2zSr6wLg3Pz+yQ+G3e9BASVkLYxdYGTDFH1pMmfas9SEI7V4I+j8DaXmL8bucSRakmcQdmDMPGiA7mvIhSAlprzCrdxM7CHeUC6MPLN1fmFFcc9kyO/ved69j/651MWC83GgxSJ15L80U+DQzmrSW8xg=="},
|
||||
"mrenclave": "e3c2f2a5b840d89e069acaffcadb6510ef866a73d3a9ee57100ed5f8646ee4bb",
|
||||
"user_data": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
}"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_verifier_bad_platform_info_blob() {
|
||||
verify_attestation(
|
||||
r#"{
|
||||
"verify_epid_attestation": {
|
||||
"report": {"report":{"id":"5246688123689513540899231107533660789","timestamp":"2024-02-07T17:06:23.913745","version":4,"epidPseudonym":"+CUyIi74LPqS6M0NF7YrSxLqPdX3MKs6D6LIPqRG/ZEB4WmxZVvxAJwdwg/0m9cYnUUQguLnJotthX645lAogfJgO8Xg5/91lSegwyUKvHmKgtjOHX/YTbVe/wmgWiBdaL+KmarY0Je459Px/FqGLWLsAF7egPAJRd1Xn88Znrs=","advisoryURL":"https://security-center.intel.com","advisoryIDs":["INTEL-SA-00161","INTEL-SA-00219","INTEL-SA-00289","INTEL-SA-00334","INTEL-SA-00615"],"isvEnclaveQuoteStatus":"CONFIGURATION_AND_SW_HARDENING_NEEDED","platformInfoBlob":"150200650000080000141402040180070000000000000000000D00000C000000020000000000000CB0F08115F3DE71AE97980FE5E10B042054930ACE356C79EC44603D3F890756EC6ED73927A7C58CDE9AF1E754AEC77E335E8D80294407936BEB6404F27669FF7BB1","isvEnclaveQuoteBody":"AgABALAMAAAPAA8AAAAAAFHK9aSLRQ1iSu/jKG0xSJQAAAAAAAAAAAAAAAAAAAAAFBQCBwGAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAHAAAAAAAAAOPC8qW4QNieBprK/8rbZRDvhmpz06nuVxAO1fhkbuS7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc8uUpEUEPvz8ZkFapjVh5WlWaLoAJM/f80T0EhGInHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRE7C+d+1dDWhoDsdyBrjVh+1AZ5txMhzN1UBeTVSmggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},"reportsig":"YaY4SPvkfR4P2E8A5huutCeS+vY/ir+xq6disalNfNtAcUyOIOqTPVXhAZgY1M5B47Hjj1oYWf2qC2w+dnj7VcZjzO9oR0pJYdA+A7jaVrNzH2eXA79yICkuU8WE/x58I0j5vjXLoHXahaKlpZkMeTphqBY8u+FTVSdP3cWPho4viPapTfQRuEWmYq4KIq2zSr6wLg3Pz+yQ+G3e9BASVkLYxdYGTDFH1pMmfas9SEI7V4I+j8DaXmL8bucSRakmcQdmDMPGiA7mvIhSAlprzCrdxM7CHeUC6MPLN1fmFFcc9kyO/ved69j/651MWC83GgxSJ15L80U+DQzmrSW8xg=="},
|
||||
"mrenclave": "e3c2f2a5b840d89e069acaffcadb6510ef866a73d3a9ee57100ed5f8646ee4bb",
|
||||
"user_data": "9113b0be77ed5d0d68680ec77206b8d587ed40679b71321ccdd5405e4d54a6820000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
}"#,
|
||||
)
|
||||
}
|
||||
}
|
23
bisenzone-cw-mvp/packages/quartz-tee-ra/src/lib.rs
Normal file
23
bisenzone-cw-mvp/packages/quartz-tee-ra/src/lib.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
#![warn(
|
||||
clippy::checked_conversions,
|
||||
clippy::panic,
|
||||
clippy::panic_in_result_fn,
|
||||
clippy::unwrap_used,
|
||||
rust_2018_idioms,
|
||||
unused_lifetimes
|
||||
)]
|
||||
#![deny(
|
||||
trivial_casts,
|
||||
trivial_numeric_casts,
|
||||
unused_import_braces,
|
||||
unused_qualifications,
|
||||
warnings
|
||||
)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
pub mod intel_sgx;
|
||||
|
||||
pub use intel_sgx::{
|
||||
epid::{types::IASReport, verifier::verify as verify_epid_attestation},
|
||||
Error,
|
||||
};
|
23
bisenzone-cw-mvp/scripts/build-contract.sh
Executable file
23
bisenzone-cw-mvp/scripts/build-contract.sh
Executable file
|
@ -0,0 +1,23 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Build and optimize the contract to output a WASM binary that can be deployed to a CosmWasm chain.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if ! [ -f "Cargo.toml" ]; then
|
||||
echo "❌ Error: Cannot find 'Cargo.toml' in current directory. Make sure this command is run from the contract's source directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "👷 Building and optimizing the contract..."
|
||||
echo "==========================================="
|
||||
|
||||
RUSTFLAGS='-C link-arg=-s' cargo wasm
|
||||
|
||||
docker run --rm -v "$(pwd)":/code \
|
||||
--mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \
|
||||
--mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
|
||||
cosmwasm/rust-optimizer:0.15.0
|
||||
|
||||
echo ""
|
||||
echo "🎉 Contract build and optimization completed successfully!"
|
73
bisenzone-cw-mvp/scripts/deploy-contract.sh
Executable file
73
bisenzone-cw-mvp/scripts/deploy-contract.sh
Executable file
|
@ -0,0 +1,73 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Deploy the specified contract's `WASM_BIN` to the chain specified by `CHAIN_ID` using the `USER_ADDR` account.
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 WASM_BIN [COUNT]"
|
||||
echo "Example: $0 artifacts/cofi_karma_game.wasm"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "❌ Error: Missing WASM_BIN parameter. Please check if all parameters were specified."
|
||||
usage
|
||||
fi
|
||||
|
||||
if [ "$#" -gt 9 ]; then
|
||||
echo "❌ Error: Incorrect number of parameters."
|
||||
usage
|
||||
fi
|
||||
|
||||
USER_ADDR=${USER_ADDR:-$(wasmd keys show -a admin)}
|
||||
WASM_BIN="$1"
|
||||
CHAIN_ID=${CHAIN_ID:-testing}
|
||||
NODE_URL=${NODE_URL:-127.0.0.1:26657}
|
||||
LABEL=${LABEL:-bisenzone-mvp}
|
||||
COUNT=${COUNT:-0}
|
||||
INSTANTIATE_MSG=${INSTANTIATE_MSG:-"{}"}
|
||||
|
||||
TXFLAG="--chain-id ${CHAIN_ID} --gas-prices 0.0025ucosm --gas auto --gas-adjustment 1.3"
|
||||
|
||||
CMD="wasmd --node http://$NODE_URL"
|
||||
|
||||
echo "🚀 Deploying WASM contract '${WASM_BIN}' on chain '${CHAIN_ID}' using account '${USER_ADDR}'..."
|
||||
echo "===================================================================="
|
||||
|
||||
RES=$($CMD tx wasm store "$WASM_BIN" --from "$USER_ADDR" $TXFLAG -y --output json)
|
||||
TX_HASH=$(echo $RES | jq -r '.["txhash"]')
|
||||
|
||||
while ! $CMD query tx $TX_HASH &> /dev/null; do
|
||||
echo "... 🕐 waiting for contract to deploy"
|
||||
sleep 1
|
||||
done
|
||||
|
||||
RES=$($CMD query tx "$TX_HASH" --output json)
|
||||
CODE_ID=$(echo $RES | jq -r '.logs[0].events[1].attributes[1].value')
|
||||
|
||||
echo ""
|
||||
echo "🚀 Instantiating contract with the following parameters:"
|
||||
echo "--------------------------------------------------------"
|
||||
echo "Label: ${LABEL}"
|
||||
echo "--------------------------------------------------------"
|
||||
|
||||
RES=$($CMD tx wasm instantiate "$CODE_ID" "$INSTANTIATE_MSG" --from "$USER_ADDR" --label $LABEL $TXFLAG -y --no-admin --output json)
|
||||
TX_HASH=$(echo $RES | jq -r '.["txhash"]')
|
||||
|
||||
|
||||
echo ""
|
||||
while ! $CMD query tx $TX_HASH &> /dev/null; do
|
||||
echo "... 🕐 waiting for contract to be queryable"
|
||||
sleep 1
|
||||
done
|
||||
|
||||
RES=$($CMD query wasm list-contract-by-code "$CODE_ID" --output json)
|
||||
CONTRACT=$(echo $RES | jq -r '.contracts[0]')
|
||||
|
||||
echo "🚀 Successfully deployed and instantiated contract!"
|
||||
echo "🔗 Chain ID: ${CHAIN_ID}"
|
||||
echo "🆔 Code ID: ${CODE_ID}"
|
||||
echo "📌 Contract Address: ${CONTRACT}"
|
||||
echo "🔑 Contract Key: ${KEY}"
|
||||
echo "🔖 Contract Label: ${LABEL}"
|
26
bisenzone-cw-mvp/scripts/init-node.sh
Executable file
26
bisenzone-cw-mvp/scripts/init-node.sh
Executable file
|
@ -0,0 +1,26 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Initialize a wasmd node that can host the MVP CosmWasm smart contract.
|
||||
# Also creates a validator account and adds default genesis accounts with sufficient tokens for testing (stake and fees)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ADMIN=${ADMIN:-$(wasmd keys show -a admin)}
|
||||
ALICE=${ALICE:-$(wasmd keys show -a alice)}
|
||||
BOB=${BOB:-$(wasmd keys show -a bob)}
|
||||
CHARLIE=${CHARLIE:-$(wasmd keys show -a charlie)}
|
||||
|
||||
echo "Remove old docker volume (if it exists)..."
|
||||
docker volume rm -f wasmd_data
|
||||
|
||||
|
||||
echo ""
|
||||
echo "Setup wasmd (with validator and default genesis accounts)..."
|
||||
docker run --rm -it \
|
||||
--mount type=volume,source=wasmd_data,target=/root \
|
||||
--name wasmd \
|
||||
cosmwasm/wasmd:v0.44.0 \
|
||||
/bin/sh -c "sed -i 's/1000000000/12000000000000/g' /opt/setup_wasmd.sh;
|
||||
/opt/setup_wasmd.sh "$ADMIN" "$ALICE" "$BOB" "$CHARLIE";" \
|
||||
|
||||
|
10
bisenzone-cw-mvp/scripts/keygen.sh
Executable file
10
bisenzone-cw-mvp/scripts/keygen.sh
Executable file
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Generate keys for testing.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
wasmd keys add admin
|
||||
wasmd keys add alice
|
||||
wasmd keys add bob
|
||||
wasmd keys add charlie
|
26
bisenzone-cw-mvp/scripts/run-node.sh
Executable file
26
bisenzone-cw-mvp/scripts/run-node.sh
Executable file
|
@ -0,0 +1,26 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Run a previously initialized wasmd node.
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
docker volume inspect wasmd_data >/dev/null 2>&1
|
||||
RESULT=$?
|
||||
if [ $RESULT -eq 1 ]; then
|
||||
echo "wasmd isn't initialized - run 'init-node.sh' first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Starting wasmd node"
|
||||
|
||||
docker run --rm -it -p 26657:26657 -p 26656:26656 -p 1317:1317 -p 9090:9090 \
|
||||
--mount type=volume,source=wasmd_data,target=/root \
|
||||
--name wasmd \
|
||||
cosmwasm/wasmd:v0.44.0 \
|
||||
/bin/sh -c "sed -i 's/enabled-unsafe-cors = false/enabled-unsafe-cors = true/g' /root/.wasmd/config/app.toml;
|
||||
sed -i 's/enable = false/enable = true/g' /root/.wasmd/config/app.toml;
|
||||
sed -i 's/rpc-max-body-bytes = 1000000$/rpc-max-body-bytes = 1000000000/g' /root/.wasmd/config/app.toml;
|
||||
sed -i 's/cors_allowed_origins = \[\]/cors_allowed_origins = \[\"*\"\]/g' /root/.wasmd/config/config.toml;
|
||||
sed -i 's/max_body_bytes = 1000000$/max_body_bytes = 1000000000/g' /root/.wasmd/config/config.toml;
|
||||
sed -i 's/max_tx_bytes = 1048576$/max_tx_bytes = 104857600/g' /root/.wasmd/config/config.toml;
|
||||
/opt/run_wasmd.sh"
|
Loading…
Reference in a new issue