Skip to content
This repository has been archived by the owner on May 9, 2022. It is now read-only.

Commit

Permalink
Merge pull request #94 from registreerocks/he-sample-functions
Browse files Browse the repository at this point in the history
Add basic sample functions
  • Loading branch information
longtomjr authored Jun 17, 2021
2 parents 233ce7a + 30068b8 commit 3a3ec1d
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 0 deletions.
1 change: 1 addition & 0 deletions rtc_exec_enclave/Cargo.lock

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

1 change: 1 addition & 0 deletions rtc_exec_enclave/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ cbindgen = "0.19.0"

# See "Pinning SGX dependencies" in HACKING.md
[target.'cfg(not(target_env = "sgx"))'.dependencies]
sgx_tcrypto = { git = "https://github.com/apache/incubator-teaclave-sgx-sdk.git", rev = "b9d1bda" }
sgx_types = { git = "https://github.com/apache/incubator-teaclave-sgx-sdk.git", rev = "b9d1bda", features = ["extra_traits"] }
sgx_tstd = { git = "https://github.com/apache/incubator-teaclave-sgx-sdk.git", rev = "b9d1bda", features = ["backtrace"] }

Expand Down
51 changes: 51 additions & 0 deletions rtc_exec_enclave/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,61 @@
#![crate_type = "staticlib"]
#![no_std]
#![feature(array_chunks)]
#![deny(unsafe_op_in_unsafe_fn)]
#![deny(clippy::mem_forget)]

mod sample_functions;
mod types;

#[cfg(not(target_env = "sgx"))]
extern crate sgx_tstd as std;

use std::boxed::Box;
use std::vec;

pub use rtc_tenclave::dh::*;
pub use rtc_tenclave::enclave::*;

use crate::types::*;

pub struct Token {
binary_hash: [u8; 32],
}

#[allow(clippy::result_unit_err)]
pub fn request_execution(token: Token, _params: ()) -> Result<Box<[u8]>, ()> {
let exec_module = match get_module_by_id(token.binary_hash) {
Some(val) => val,
None => return Err(()),
};
let data = get_data(&token);

// as_ptr() does not take ownership, so the data will be dropped at the end of this function
// Safety:
// As long as `data` is valid, this should be safe.
// Memory will be cleaned up when `data` goes out of scope, which will be after the unsafe function call.
let result = unsafe { exec_module.call(data.as_ptr(), data.len()) };

match result {
Ok(val) => Ok(val),
// XXX: The error handling here should take into account the Traps from WASM once we call
// WASM functions
Err(_) => Err(()),
}
}

// XXX: This is placeholder until we completed the data retrieval flow and know what values
// we need to pass through to the data enclave
fn get_data(_token: &Token) -> Box<[u8]> {
vec![123; 43].into_boxed_slice()
}

// XXX: The implementation is only for the sample functions currently
pub(crate) fn get_module_by_id(module_id: [u8; 32]) -> Option<Box<dyn ExecModule>> {
use sample_functions::*;
match module_id {
SHA256_HASH_MODULE_ID => Some(Box::new(Sha256HashModule)),
MEDIAN_MODULE_ID => Some(Box::new(MedianModule)),
_ => None,
}
}
94 changes: 94 additions & 0 deletions rtc_exec_enclave/src/sample_functions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use core::cmp::Ordering;
use core::mem::size_of;
use core::slice;
use std::boxed::Box;
use std::vec::Vec;

use crate::types::*;

pub(crate) trait SampleExecModule {
fn call_safe(&self, dataset: &[u8]) -> ExecResult;
}

impl<T> ExecModule for T
where
T: SampleExecModule,
{
unsafe fn call(&self, dataset_ptr: *const u8, dataset_len: usize) -> ExecResult {
let dataset = unsafe { slice::from_raw_parts(dataset_ptr, dataset_len) };
self.call_safe(dataset)
}
}

pub(crate) const SHA256_HASH_MODULE_ID: [u8; 32] = [1u8; 32];
pub(crate) struct Sha256HashModule;

impl SampleExecModule for Sha256HashModule {
fn call_safe(&self, dataset: &[u8]) -> ExecResult {
match sgx_tcrypto::rsgx_sha256_slice(dataset) {
Ok(res) => Ok(res.to_vec().into_boxed_slice()),
Err(_) => Err(()),
}
}
}

pub(crate) const MEDIAN_MODULE_ID: [u8; 32] = [2u8; 32];
pub(crate) struct MedianModule;

impl SampleExecModule for MedianModule {
fn call_safe(&self, dataset: &[u8]) -> ExecResult {
let mut float_dataset: Vec<f64> = if dataset.len() % size_of::<f64>() == 0 {
// Safety: dataset.len() should be aligned with the size of f64,
// so the array_chucks iterator should have no remainder().
dataset
.array_chunks()
.map(|x| f64::from_ne_bytes(*x))
.collect()
} else {
// Bail out: dataset.len() is not a multiple of the size of f64.
return Err(());
};

let median = median(&mut float_dataset).ok_or(())?;
let median_bytes = median.to_ne_bytes();

Ok(Box::new(median_bytes))
}
}

fn median(data: &mut [f64]) -> Option<f64> {
let len = data.len();
// If len is 0 we cannot calculate a median
if len == 0 {
return None;
};

// No well-defined median if data contains infinities or NaN.
// TODO: Consider something like <https://crates.io/crates/ordered-float>?
if !data.iter().all(|n| n.is_finite()) {
return None;
}

let mid = len / 2;

// Safety: is_finite checked above
let (less, &mut m1, _) = data.select_nth_unstable_by(mid, |a, b| unsafe { finite_cmp(a, b) });

let median = if len % 2 == 1 {
m1
} else {
// Safety: is_finite checked above
let (_, &mut m2, _) =
less.select_nth_unstable_by(mid - 1, |a, b| unsafe { finite_cmp(a, b) });
(m1 + m2) / 2.0
};
Some(median)
}

/// Compare finite floats.
/// # Safety
/// Caller must ensure values are finite (or at least not NaN).
unsafe fn finite_cmp(a: &f64, b: &f64) -> Ordering {
a.partial_cmp(b)
.unwrap_or_else(|| panic!("finite_cmp({:?}, {:?}): not comparable", a, b))
}
13 changes: 13 additions & 0 deletions rtc_exec_enclave/src/types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use std::boxed::Box;

pub(crate) type CallReturnValue = Box<[u8]>;

pub(crate) type ExecResult = core::result::Result<CallReturnValue, ()>;

pub(crate) trait ExecModule {
/// Calls the entry function of a module with the provided dataset and return the result
///
/// # Safety
/// The caller must ensure that `dataset_ptr` is a valid pointer to a `u8` slice of `dataset_len`
unsafe fn call(&self, dataset_ptr: *const u8, dataset_len: usize) -> ExecResult;
}

0 comments on commit 3a3ec1d

Please sign in to comment.