Skip to content

Commit 5e8e40a

Browse files
committed
BLD: building enclave+app (WIP)
1 parent 4a22b9b commit 5e8e40a

28 files changed

+1676
-1
lines changed

.gitignore

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@ Cargo.lock
1212
*.so.*
1313

1414
**/target
15+
*.wasm
16+
17+
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
18+
# More information here https://doc.rust-lang.org/cargo/faq.html#why-do-binaries-have-cargolock-in-version-control-but-not-libraries
19+
Cargo.lock
20+
!*/app/Cargo.lock
21+
!*/enclave/Cargo.lock
22+
.Cargo.toml.swp
23+
24+
# These are backup files generated by rustfmt
25+
**/*.rs.bk
1526

1627
#generated assembly
1728
third_party/ring/pregenerated
@@ -24,5 +35,77 @@ bazel-out
2435
bazel-rust-sgx-sdk
2536
bazel-testlogs
2637

38+
# SGX Files
39+
Enclave_u.c
40+
Enclave_u.h
41+
Enclave_t.c
42+
Enclave_t.h
43+
bin/
44+
lib/
45+
46+
# enigma-types
47+
enigma-types.h
48+
49+
# Prerequisites
50+
*.d
51+
52+
# Compiled Object files
53+
*.slo
54+
*.lo
55+
*.o
56+
*.obj
57+
58+
# Precompiled Headers
59+
*.gch
60+
*.pch
61+
62+
# Compiled Dynamic libraries
63+
*.so
64+
*.dylib
65+
*.dll
66+
67+
68+
# Compiled Static libraries
69+
*.lai
70+
*.la
71+
*.a
72+
*.lib
73+
74+
# Executables
75+
*.exe
76+
*.out
77+
*.app
78+
2779
#Node/NPM
28-
node_modules/
80+
node_modules/
81+
82+
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
83+
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
84+
85+
# CMake
86+
cmake-build-debug/
87+
cmake-build-release/
88+
89+
# File-based project format
90+
*.iws
91+
92+
# IDEs
93+
out/
94+
.idea/
95+
.vscode/
96+
**/*.iml
97+
98+
# mpeltonen/sbt-idea plugin
99+
.idea_modules/
100+
101+
# JIRA plugin
102+
atlassian-ide-plugin.xml
103+
104+
# Crashlytics plugin (for Android Studio and IntelliJ)
105+
com_crashlytics_export_strings.xml
106+
crashlytics.properties
107+
crashlytics-build.properties
108+
fabric.properties
109+
110+
/target
111+
**/*.rs.bk

enclave/enigma-types/Cargo.toml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# I use package renaming to import 2 libraries with the same name but from different sources (1 for SGX and 1 for regular std)
2+
# Then in the code you can rename them back (under a cfg condition) to the same name to use abstractly.
3+
4+
[package]
5+
name = "enigma-types"
6+
version = "0.3.0"
7+
authors = ["Elichai Turkel <elichai@enigma.co>"]
8+
edition = "2018"
9+
categories = ["no-std"]
10+
11+
[dependencies]
12+
rustc-hex = { version = "2.0.1", default-features = false }
13+
arrayvec = { version = "0.4.10", default-features = false }
14+
serde_sgx = { package = "serde", git = "https://github.com/mesalock-linux/serde-sgx.git", rev = "sgx_1.0.9", optional = true }
15+
serde_std = { package = "serde", version = "1.0", default-features = false, optional = true }
16+
17+
[build-dependencies]
18+
cbindgen = "0.8"
19+
20+
[features]
21+
default = ["serde_std/derive"] # This library is no_std with the default features.
22+
std = ["serde_std/std", "serde_std/derive"]
23+
alloc = ["serde_std/alloc", "serde_std/derive"]
24+
sgx = ["serde_sgx", "serde_sgx/derive"]

enclave/enigma-types/build.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// client/build.rs
2+
3+
use cbindgen::Language;
4+
use std::{env, path::PathBuf};
5+
6+
fn main() {
7+
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
8+
let package_name = env::var("CARGO_PKG_NAME").unwrap();
9+
let output_file = target_dir().join(format!("{}.h", package_name)).display().to_string();
10+
11+
cbindgen::Builder::new()
12+
.with_no_includes()
13+
.with_sys_include("stdbool.h")
14+
.with_language(Language::C)
15+
.include_item("EnclaveReturn")
16+
.include_item("ResultStatus")
17+
.include_item("ExecuteResult")
18+
.include_item("Hash256")
19+
.include_item("StateKey")
20+
.include_item("ContractAddress")
21+
.include_item("MsgID")
22+
.include_item("PubKey")
23+
.include_item("RawPointer")
24+
.with_crate(&crate_dir)
25+
.generate()
26+
.expect("Unable to generate bindings")
27+
.write_to_file(&output_file);
28+
}
29+
30+
/// Find the location of the `target/` directory. Note that this may be
31+
/// overridden by `cmake`, so we also need to check the `CARGO_TARGET_DIR`
32+
/// variable.
33+
fn target_dir() -> PathBuf {
34+
let mut target = PathBuf::from(env::var("OUT_DIR").unwrap());
35+
target.pop();
36+
target.pop();
37+
target.pop();
38+
target.pop();
39+
target.pop();
40+
41+
target
42+
}

enclave/enigma-types/src/hash.rs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
//! # Hash Module
2+
//! This module provides a struct meant for containing Hashes (Kecack256 or Sha256).
3+
4+
use core::ops::{Deref, DerefMut};
5+
use rustc_hex::{FromHex, FromHexError};
6+
use arrayvec::ArrayVec;
7+
use crate::serde::{Serialize, Deserialize};
8+
9+
/// This struct is basically a wrapper over `[u8; 32]`, and is meant to be returned from whatever hashing functions we use.
10+
/// `#[repr(C)]` is a Rust feature which makes the struct be aligned just like C structs.
11+
/// See [`Repr(C)`][https://doc.rust-lang.org/nomicon/other-reprs.html]
12+
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Default)]
13+
#[serde(crate = "crate::serde")]
14+
#[repr(C)]
15+
pub struct Hash256([u8; 32]);
16+
17+
18+
impl Hash256 {
19+
/// This method exposes rust's built in [`copy_from_slice`][https://doc.rust-lang.org/std/primitive.slice.html#method.copy_from_slice]
20+
/// Copies the elements from `src` into `self`.
21+
///
22+
/// The length of `src` must be the same as `self`.
23+
///
24+
/// # Panics
25+
///
26+
/// This function will panic if the two slices have different lengths.
27+
///
28+
/// This might not be needed since we implement `Deref` and `DerefMut` for the inner array.
29+
pub fn copy_from_slice(&mut self, src: &[u8]) {
30+
self.0.copy_from_slice(src)
31+
}
32+
33+
/// This function converts a hex string into `Hash256` type.
34+
/// the hex must not contain `0x` (as is usually the case in hexs in rust)
35+
/// if the hex length isn't 64 (which will be converted into the 32 bytes) it will return an error.
36+
pub fn from_hex(hex: &str) -> Result<Self, FromHexError> {
37+
if hex.len() != 64 {
38+
return Err(FromHexError::InvalidHexLength);
39+
}
40+
let hex_vec: ArrayVec<[u8; 32]> = hex.from_hex()?;
41+
let mut result = Self::default();
42+
result.copy_from_slice(&hex_vec);
43+
Ok(result)
44+
}
45+
46+
/// Checks if the struct contains only zeroes or not.
47+
pub fn is_zero(&self) -> bool {
48+
self.0 == [0u8;32]
49+
}
50+
}
51+
52+
53+
impl From<[u8; 32]> for Hash256 {
54+
fn from(arr: [u8; 32]) -> Self {
55+
Hash256(arr)
56+
}
57+
}
58+
59+
impl Into<[u8; 32]> for Hash256 {
60+
fn into(self) -> [u8; 32] {
61+
self.0
62+
}
63+
}
64+
65+
impl Deref for Hash256 {
66+
type Target = [u8; 32];
67+
68+
fn deref(&self) -> &[u8; 32] {
69+
&self.0
70+
}
71+
}
72+
73+
impl DerefMut for Hash256 {
74+
fn deref_mut(&mut self) -> &mut [u8; 32] {
75+
&mut self.0
76+
}
77+
}
78+
79+
impl AsRef<[u8]> for Hash256 {
80+
fn as_ref(&self) -> &[u8] {
81+
&self.0
82+
}
83+
}
84+
85+
impl AsMut<[u8]> for Hash256 {
86+
fn as_mut(&mut self) -> &mut [u8] {
87+
&mut self.0
88+
}
89+
}
90+
91+
#[cfg(test)]
92+
mod test {
93+
use super::Hash256;
94+
#[test]
95+
fn test_hex_succeed() {
96+
let a = "0101010101010101010101010101010101010101010101010101010101010101";
97+
Hash256::from_hex(&a).unwrap();
98+
}
99+
100+
#[should_panic]
101+
#[test]
102+
fn test_hex_long() {
103+
let a = "02020202020202020202020202020202020202020202020202020202020202020202024444020202020202";
104+
Hash256::from_hex(&a).unwrap();
105+
}
106+
}

enclave/enigma-types/src/lib.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
2+
#![deny(unused_extern_crates, missing_docs, warnings)]
3+
//! # Enigma Types
4+
//! This library is meant to supply all the types that are specific to our protocol. <br>
5+
//! Inside of this library I abstracted the std as `localstd` so that you can use it without knowing if it's `sgx_tstd` or regular std.
6+
//! *But* Unlike other crates this isn't just abstracting 2 different std's,
7+
//! but this crate is expected to work even without std at all(except some parts maybe).
8+
//!
9+
//! in the `build.rs` I use `cbindgen` to auto generate `enigma-types.h` header so it can be included into the edl.
10+
//! that way we can pass rust structs through the SGX bridge(which is C)
11+
//!
12+
//! This crate is Rust 2018 Edition,
13+
//! meaning there's no `extern crate` and `use` statements need to start with `crate`/`self`/`super`.
14+
15+
16+
pub mod traits;
17+
mod types;
18+
mod hash;
19+
20+
#[cfg(all(feature = "sgx", not(feature = "std")))]
21+
use serde_sgx as serde;
22+
23+
#[cfg(not(feature = "sgx"))]
24+
use serde_std as serde;
25+
26+
use crate::traits::SliceCPtr;
27+
pub use crate::types::*;
28+
29+
/// This is a bit safer wrapper of [`core::ptr::copy_nonoverlapping`]
30+
/// it checks that the src len is at least as big as `count` otherwise it will panic.
31+
/// *and* it uses [`SliceCPtr`](crate::traits::SliceCPtr) trait to pass a C compatible pointer.
32+
pub unsafe fn write_ptr<T>(src: &[T], dst: *mut T, count: usize) {
33+
if src.len() > count {
34+
unimplemented!()
35+
}
36+
core::ptr::copy_nonoverlapping(src.as_c_ptr(), dst, src.len());
37+
}

enclave/enigma-types/src/traits.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//! # Traits module
2+
//! This module should provide low level traits that are required on both sides of the SGX.
3+
//! right now it only contains the [`SliceCPtr`] trait which is used to *always* provide valid C pointers.
4+
5+
static EMPTY: [u8; 1] = [0];
6+
7+
/// This trait provides an interface into `C` like pointers.
8+
/// in Rust if you try to get a pointer to an empty vector you'll get:
9+
/// 0x0000000000000001 OR 0x0000000000000000, although bear in mind this *isn't* officially defined.
10+
/// this behavior is UB in C's `malloc`, passing an invalid pointer with size 0 to `malloc` is implementation defined.
11+
/// in the case of Intel's + GCC what we observed is a Segmentation Fault.
12+
/// this is why if the vec/slice is empty we use this trait to pass a pointer to a stack allocated static `[0]` array.
13+
/// this will make the pointer valid, and when the len is zero
14+
/// `malloc` won't allocate anything but also won't produce a SegFault
15+
pub trait SliceCPtr {
16+
/// The Target for the trait.
17+
/// this trait can't be generic because it should only be implemented once per type
18+
/// (See [Associated Types][https://doc.rust-lang.org/rust-by-example/generics/assoc_items/types.html])
19+
type Target;
20+
/// This function is what will produce a valid C pointer to the target
21+
/// even if the target is 0 sized (and rust will produce a C *invalid* pointer for it )
22+
fn as_c_ptr(&self) -> *const Self::Target;
23+
}
24+
25+
impl<T> SliceCPtr for [T] {
26+
type Target = T;
27+
fn as_c_ptr(&self) -> *const Self::Target {
28+
if self.is_empty() {
29+
EMPTY.as_ptr() as *const _
30+
} else {
31+
self.as_ptr()
32+
}
33+
}
34+
}
35+
36+
impl SliceCPtr for str {
37+
type Target = u8;
38+
fn as_c_ptr(&self) -> *const Self::Target {
39+
if self.is_empty() {
40+
EMPTY.as_ptr() as *const _
41+
} else {
42+
self.as_ptr()
43+
}
44+
}
45+
}

0 commit comments

Comments
 (0)