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

Commit 3a3ec1d

Browse files
authored
Merge pull request #94 from registreerocks/he-sample-functions
Add basic sample functions
2 parents 233ce7a + 30068b8 commit 3a3ec1d

File tree

5 files changed

+160
-0
lines changed

5 files changed

+160
-0
lines changed

rtc_exec_enclave/Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rtc_exec_enclave/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ cbindgen = "0.19.0"
1515

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

rtc_exec_enclave/src/lib.rs

+51
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,61 @@
11
#![crate_type = "staticlib"]
22
#![no_std]
3+
#![feature(array_chunks)]
34
#![deny(unsafe_op_in_unsafe_fn)]
45
#![deny(clippy::mem_forget)]
56

7+
mod sample_functions;
8+
mod types;
9+
610
#[cfg(not(target_env = "sgx"))]
711
extern crate sgx_tstd as std;
812

13+
use std::boxed::Box;
14+
use std::vec;
15+
916
pub use rtc_tenclave::dh::*;
1017
pub use rtc_tenclave::enclave::*;
18+
19+
use crate::types::*;
20+
21+
pub struct Token {
22+
binary_hash: [u8; 32],
23+
}
24+
25+
#[allow(clippy::result_unit_err)]
26+
pub fn request_execution(token: Token, _params: ()) -> Result<Box<[u8]>, ()> {
27+
let exec_module = match get_module_by_id(token.binary_hash) {
28+
Some(val) => val,
29+
None => return Err(()),
30+
};
31+
let data = get_data(&token);
32+
33+
// as_ptr() does not take ownership, so the data will be dropped at the end of this function
34+
// Safety:
35+
// As long as `data` is valid, this should be safe.
36+
// Memory will be cleaned up when `data` goes out of scope, which will be after the unsafe function call.
37+
let result = unsafe { exec_module.call(data.as_ptr(), data.len()) };
38+
39+
match result {
40+
Ok(val) => Ok(val),
41+
// XXX: The error handling here should take into account the Traps from WASM once we call
42+
// WASM functions
43+
Err(_) => Err(()),
44+
}
45+
}
46+
47+
// XXX: This is placeholder until we completed the data retrieval flow and know what values
48+
// we need to pass through to the data enclave
49+
fn get_data(_token: &Token) -> Box<[u8]> {
50+
vec![123; 43].into_boxed_slice()
51+
}
52+
53+
// XXX: The implementation is only for the sample functions currently
54+
pub(crate) fn get_module_by_id(module_id: [u8; 32]) -> Option<Box<dyn ExecModule>> {
55+
use sample_functions::*;
56+
match module_id {
57+
SHA256_HASH_MODULE_ID => Some(Box::new(Sha256HashModule)),
58+
MEDIAN_MODULE_ID => Some(Box::new(MedianModule)),
59+
_ => None,
60+
}
61+
}
+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
use core::cmp::Ordering;
2+
use core::mem::size_of;
3+
use core::slice;
4+
use std::boxed::Box;
5+
use std::vec::Vec;
6+
7+
use crate::types::*;
8+
9+
pub(crate) trait SampleExecModule {
10+
fn call_safe(&self, dataset: &[u8]) -> ExecResult;
11+
}
12+
13+
impl<T> ExecModule for T
14+
where
15+
T: SampleExecModule,
16+
{
17+
unsafe fn call(&self, dataset_ptr: *const u8, dataset_len: usize) -> ExecResult {
18+
let dataset = unsafe { slice::from_raw_parts(dataset_ptr, dataset_len) };
19+
self.call_safe(dataset)
20+
}
21+
}
22+
23+
pub(crate) const SHA256_HASH_MODULE_ID: [u8; 32] = [1u8; 32];
24+
pub(crate) struct Sha256HashModule;
25+
26+
impl SampleExecModule for Sha256HashModule {
27+
fn call_safe(&self, dataset: &[u8]) -> ExecResult {
28+
match sgx_tcrypto::rsgx_sha256_slice(dataset) {
29+
Ok(res) => Ok(res.to_vec().into_boxed_slice()),
30+
Err(_) => Err(()),
31+
}
32+
}
33+
}
34+
35+
pub(crate) const MEDIAN_MODULE_ID: [u8; 32] = [2u8; 32];
36+
pub(crate) struct MedianModule;
37+
38+
impl SampleExecModule for MedianModule {
39+
fn call_safe(&self, dataset: &[u8]) -> ExecResult {
40+
let mut float_dataset: Vec<f64> = if dataset.len() % size_of::<f64>() == 0 {
41+
// Safety: dataset.len() should be aligned with the size of f64,
42+
// so the array_chucks iterator should have no remainder().
43+
dataset
44+
.array_chunks()
45+
.map(|x| f64::from_ne_bytes(*x))
46+
.collect()
47+
} else {
48+
// Bail out: dataset.len() is not a multiple of the size of f64.
49+
return Err(());
50+
};
51+
52+
let median = median(&mut float_dataset).ok_or(())?;
53+
let median_bytes = median.to_ne_bytes();
54+
55+
Ok(Box::new(median_bytes))
56+
}
57+
}
58+
59+
fn median(data: &mut [f64]) -> Option<f64> {
60+
let len = data.len();
61+
// If len is 0 we cannot calculate a median
62+
if len == 0 {
63+
return None;
64+
};
65+
66+
// No well-defined median if data contains infinities or NaN.
67+
// TODO: Consider something like <https://crates.io/crates/ordered-float>?
68+
if !data.iter().all(|n| n.is_finite()) {
69+
return None;
70+
}
71+
72+
let mid = len / 2;
73+
74+
// Safety: is_finite checked above
75+
let (less, &mut m1, _) = data.select_nth_unstable_by(mid, |a, b| unsafe { finite_cmp(a, b) });
76+
77+
let median = if len % 2 == 1 {
78+
m1
79+
} else {
80+
// Safety: is_finite checked above
81+
let (_, &mut m2, _) =
82+
less.select_nth_unstable_by(mid - 1, |a, b| unsafe { finite_cmp(a, b) });
83+
(m1 + m2) / 2.0
84+
};
85+
Some(median)
86+
}
87+
88+
/// Compare finite floats.
89+
/// # Safety
90+
/// Caller must ensure values are finite (or at least not NaN).
91+
unsafe fn finite_cmp(a: &f64, b: &f64) -> Ordering {
92+
a.partial_cmp(b)
93+
.unwrap_or_else(|| panic!("finite_cmp({:?}, {:?}): not comparable", a, b))
94+
}

rtc_exec_enclave/src/types.rs

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use std::boxed::Box;
2+
3+
pub(crate) type CallReturnValue = Box<[u8]>;
4+
5+
pub(crate) type ExecResult = core::result::Result<CallReturnValue, ()>;
6+
7+
pub(crate) trait ExecModule {
8+
/// Calls the entry function of a module with the provided dataset and return the result
9+
///
10+
/// # Safety
11+
/// The caller must ensure that `dataset_ptr` is a valid pointer to a `u8` slice of `dataset_len`
12+
unsafe fn call(&self, dataset_ptr: *const u8, dataset_len: usize) -> ExecResult;
13+
}

0 commit comments

Comments
 (0)