Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 84 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@ Cargo.lock
*.so.*

**/target
*.wasm

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/faq.html#why-do-binaries-have-cargolock-in-version-control-but-not-libraries
Cargo.lock
!*/app/Cargo.lock
!*/enclave/Cargo.lock
.Cargo.toml.swp

# These are backup files generated by rustfmt
**/*.rs.bk

#generated assembly
third_party/ring/pregenerated
Expand All @@ -24,5 +35,77 @@ bazel-out
bazel-rust-sgx-sdk
bazel-testlogs

# SGX Files
Enclave_u.c
Enclave_u.h
Enclave_t.c
Enclave_t.h
bin/
lib/

# enigma-types
enigma-types.h

# Prerequisites
*.d

# Compiled Object files
*.slo
*.lo
*.o
*.obj

# Precompiled Headers
*.gch
*.pch

# Compiled Dynamic libraries
*.so
*.dylib
*.dll


# Compiled Static libraries
*.lai
*.la
*.a
*.lib

# Executables
*.exe
*.out
*.app

#Node/NPM
node_modules/
node_modules/

# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839

# CMake
cmake-build-debug/
cmake-build-release/

# File-based project format
*.iws

# IDEs
out/
.idea/
.vscode/
**/*.iml

# mpeltonen/sbt-idea plugin
.idea_modules/

# JIRA plugin
atlassian-ide-plugin.xml

# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties

/target
**/*.rs.bk
24 changes: 24 additions & 0 deletions enclave/enigma-types/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# I use package renaming to import 2 libraries with the same name but from different sources (1 for SGX and 1 for regular std)
# Then in the code you can rename them back (under a cfg condition) to the same name to use abstractly.

[package]
name = "enigma-types"
version = "0.3.0"
authors = ["Elichai Turkel <elichai@enigma.co>"]
edition = "2018"
categories = ["no-std"]

[dependencies]
rustc-hex = { version = "2.0.1", default-features = false }
arrayvec = { version = "0.4.10", default-features = false }
serde_sgx = { package = "serde", git = "https://github.com/mesalock-linux/serde-sgx.git", rev = "sgx_1.0.9", optional = true }
serde_std = { package = "serde", version = "1.0", default-features = false, optional = true }

[build-dependencies]
cbindgen = "0.8"

[features]
default = ["serde_std/derive"] # This library is no_std with the default features.
std = ["serde_std/std", "serde_std/derive"]
alloc = ["serde_std/alloc", "serde_std/derive"]
sgx = ["serde_sgx", "serde_sgx/derive"]
42 changes: 42 additions & 0 deletions enclave/enigma-types/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// client/build.rs

use cbindgen::Language;
use std::{env, path::PathBuf};

fn main() {
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let package_name = env::var("CARGO_PKG_NAME").unwrap();
let output_file = target_dir().join(format!("{}.h", package_name)).display().to_string();

cbindgen::Builder::new()
.with_no_includes()
.with_sys_include("stdbool.h")
.with_language(Language::C)
.include_item("EnclaveReturn")
.include_item("ResultStatus")
.include_item("ExecuteResult")
.include_item("Hash256")
.include_item("StateKey")
.include_item("ContractAddress")
.include_item("MsgID")
.include_item("PubKey")
.include_item("RawPointer")
.with_crate(&crate_dir)
.generate()
.expect("Unable to generate bindings")
.write_to_file(&output_file);
}

/// Find the location of the `target/` directory. Note that this may be
/// overridden by `cmake`, so we also need to check the `CARGO_TARGET_DIR`
/// variable.
fn target_dir() -> PathBuf {
let mut target = PathBuf::from(env::var("OUT_DIR").unwrap());
target.pop();
target.pop();
target.pop();
target.pop();
target.pop();

target
}
106 changes: 106 additions & 0 deletions enclave/enigma-types/src/hash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
//! # Hash Module
//! This module provides a struct meant for containing Hashes (Kecack256 or Sha256).

use core::ops::{Deref, DerefMut};
use rustc_hex::{FromHex, FromHexError};
use arrayvec::ArrayVec;
use crate::serde::{Serialize, Deserialize};

/// This struct is basically a wrapper over `[u8; 32]`, and is meant to be returned from whatever hashing functions we use.
/// `#[repr(C)]` is a Rust feature which makes the struct be aligned just like C structs.
/// See [`Repr(C)`][https://doc.rust-lang.org/nomicon/other-reprs.html]
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Default)]
#[serde(crate = "crate::serde")]
#[repr(C)]
pub struct Hash256([u8; 32]);


impl Hash256 {
/// This method exposes rust's built in [`copy_from_slice`][https://doc.rust-lang.org/std/primitive.slice.html#method.copy_from_slice]
/// Copies the elements from `src` into `self`.
///
/// The length of `src` must be the same as `self`.
///
/// # Panics
///
/// This function will panic if the two slices have different lengths.
///
/// This might not be needed since we implement `Deref` and `DerefMut` for the inner array.
pub fn copy_from_slice(&mut self, src: &[u8]) {
self.0.copy_from_slice(src)
}

/// This function converts a hex string into `Hash256` type.
/// the hex must not contain `0x` (as is usually the case in hexs in rust)
/// if the hex length isn't 64 (which will be converted into the 32 bytes) it will return an error.
pub fn from_hex(hex: &str) -> Result<Self, FromHexError> {
if hex.len() != 64 {
return Err(FromHexError::InvalidHexLength);
}
let hex_vec: ArrayVec<[u8; 32]> = hex.from_hex()?;
let mut result = Self::default();
result.copy_from_slice(&hex_vec);
Ok(result)
}

/// Checks if the struct contains only zeroes or not.
pub fn is_zero(&self) -> bool {
self.0 == [0u8;32]
}
}


impl From<[u8; 32]> for Hash256 {
fn from(arr: [u8; 32]) -> Self {
Hash256(arr)
}
}

impl Into<[u8; 32]> for Hash256 {
fn into(self) -> [u8; 32] {
self.0
}
}

impl Deref for Hash256 {
type Target = [u8; 32];

fn deref(&self) -> &[u8; 32] {
&self.0
}
}

impl DerefMut for Hash256 {
fn deref_mut(&mut self) -> &mut [u8; 32] {
&mut self.0
}
}

impl AsRef<[u8]> for Hash256 {
fn as_ref(&self) -> &[u8] {
&self.0
}
}

impl AsMut<[u8]> for Hash256 {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0
}
}

#[cfg(test)]
mod test {
use super::Hash256;
#[test]
fn test_hex_succeed() {
let a = "0101010101010101010101010101010101010101010101010101010101010101";
Hash256::from_hex(&a).unwrap();
}

#[should_panic]
#[test]
fn test_hex_long() {
let a = "02020202020202020202020202020202020202020202020202020202020202020202024444020202020202";
Hash256::from_hex(&a).unwrap();
}
}
37 changes: 37 additions & 0 deletions enclave/enigma-types/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
#![deny(unused_extern_crates, missing_docs, warnings)]
//! # Enigma Types
//! This library is meant to supply all the types that are specific to our protocol. <br>
//! 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.
//! *But* Unlike other crates this isn't just abstracting 2 different std's,
//! but this crate is expected to work even without std at all(except some parts maybe).
//!
//! in the `build.rs` I use `cbindgen` to auto generate `enigma-types.h` header so it can be included into the edl.
//! that way we can pass rust structs through the SGX bridge(which is C)
//!
//! This crate is Rust 2018 Edition,
//! meaning there's no `extern crate` and `use` statements need to start with `crate`/`self`/`super`.


pub mod traits;
mod types;
mod hash;

#[cfg(all(feature = "sgx", not(feature = "std")))]
use serde_sgx as serde;

#[cfg(not(feature = "sgx"))]
use serde_std as serde;

use crate::traits::SliceCPtr;
pub use crate::types::*;

/// This is a bit safer wrapper of [`core::ptr::copy_nonoverlapping`]
/// it checks that the src len is at least as big as `count` otherwise it will panic.
/// *and* it uses [`SliceCPtr`](crate::traits::SliceCPtr) trait to pass a C compatible pointer.
pub unsafe fn write_ptr<T>(src: &[T], dst: *mut T, count: usize) {
if src.len() > count {
unimplemented!()
}
core::ptr::copy_nonoverlapping(src.as_c_ptr(), dst, src.len());
}
45 changes: 45 additions & 0 deletions enclave/enigma-types/src/traits.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//! # Traits module
//! This module should provide low level traits that are required on both sides of the SGX.
//! right now it only contains the [`SliceCPtr`] trait which is used to *always* provide valid C pointers.

static EMPTY: [u8; 1] = [0];

/// This trait provides an interface into `C` like pointers.
/// in Rust if you try to get a pointer to an empty vector you'll get:
/// 0x0000000000000001 OR 0x0000000000000000, although bear in mind this *isn't* officially defined.
/// this behavior is UB in C's `malloc`, passing an invalid pointer with size 0 to `malloc` is implementation defined.
/// in the case of Intel's + GCC what we observed is a Segmentation Fault.
/// this is why if the vec/slice is empty we use this trait to pass a pointer to a stack allocated static `[0]` array.
/// this will make the pointer valid, and when the len is zero
/// `malloc` won't allocate anything but also won't produce a SegFault
pub trait SliceCPtr {
/// The Target for the trait.
/// this trait can't be generic because it should only be implemented once per type
/// (See [Associated Types][https://doc.rust-lang.org/rust-by-example/generics/assoc_items/types.html])
type Target;
/// This function is what will produce a valid C pointer to the target
/// even if the target is 0 sized (and rust will produce a C *invalid* pointer for it )
fn as_c_ptr(&self) -> *const Self::Target;
}

impl<T> SliceCPtr for [T] {
type Target = T;
fn as_c_ptr(&self) -> *const Self::Target {
if self.is_empty() {
EMPTY.as_ptr() as *const _
} else {
self.as_ptr()
}
}
}

impl SliceCPtr for str {
type Target = u8;
fn as_c_ptr(&self) -> *const Self::Target {
if self.is_empty() {
EMPTY.as_ptr() as *const _
} else {
self.as_ptr()
}
}
}
Loading