├── .dockerignore ├── .drone.yml ├── .github └── ISSUE_TEMPLATE │ ├── enigma-bug-report.md │ └── enigma-feature-request.md ├── .gitignore ├── .rustfmt.toml ├── LICENSE ├── README.md ├── clone.Dockerfile ├── dockerfile ├── Dockerfile └── run.sh ├── eng-wasm ├── .cargo │ └── config ├── Cargo.toml ├── derive │ ├── .rustfmt.toml │ ├── Cargo.toml │ ├── examples │ │ ├── struct-impl.rs │ │ ├── trait-impl-rename.rs │ │ └── trait-impl.rs │ └── src │ │ ├── eth_contract.rs │ │ ├── eth_contract │ │ ├── errors.rs │ │ └── ethereum.rs │ │ ├── into_ident.rs │ │ ├── lib.rs │ │ ├── pub_interface.rs │ │ ├── pub_interface │ │ └── parse_signatures.rs │ │ └── reduce_mut.rs └── src │ ├── crypto_wasm.rs │ ├── internal_std.rs │ ├── lib.rs │ └── rand_wasm.rs ├── enigma-core ├── CHANGELOG.md ├── Makefile ├── app │ ├── Cargo.lock │ ├── Cargo.toml │ ├── build.rs │ ├── cross-test-utils │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── src │ │ ├── auto_ffi.rs │ │ ├── cli.rs │ │ ├── common_u │ │ │ ├── errors.rs │ │ │ └── mod.rs │ │ ├── db │ │ │ ├── dal.rs │ │ │ ├── iterator.rs │ │ │ ├── mod.rs │ │ │ └── primitives.rs │ │ ├── esgx │ │ │ ├── equote.rs │ │ │ ├── general.rs │ │ │ ├── mod.rs │ │ │ └── ocalls_u.rs │ │ ├── km_u.rs │ │ ├── lib.rs │ │ ├── main.rs │ │ ├── networking │ │ │ ├── ipc_listener.rs │ │ │ ├── messages.rs │ │ │ └── mod.rs │ │ └── wasm_u │ │ │ ├── mod.rs │ │ │ └── wasm.rs │ └── tests │ │ ├── evm_input_files │ │ └── input │ │ ├── integration_utils │ │ └── mod.rs │ │ ├── ipc_computation_tests.rs │ │ ├── ipc_identity_and_general_tests.rs │ │ ├── ipc_key_exchange_tests.rs │ │ ├── ipc_read_db_tests.rs │ │ └── ipc_write_db_tests.rs └── enclave │ ├── Cargo.lock │ ├── Cargo.toml │ ├── Enclave.config.xml │ ├── Enclave.edl │ ├── Enclave.lds │ ├── Enclave_private.pem │ ├── Makefile │ └── src │ ├── auto_ffi.rs │ ├── km_t │ ├── mod.rs │ ├── principal.rs │ └── users.rs │ └── lib.rs ├── enigma-crypto ├── Cargo.toml └── src │ ├── asymmetric.rs │ ├── error.rs │ ├── hash.rs │ ├── lib.rs │ ├── rand.rs │ └── symmetric.rs ├── enigma-principal ├── CHANGELOG.md ├── Makefile ├── README.md ├── app │ ├── Cargo.lock │ ├── Cargo.toml │ ├── build.rs │ ├── src │ │ ├── boot_network │ │ │ ├── config.json │ │ │ ├── deploy_scripts.rs │ │ │ ├── keys_provider_http.rs │ │ │ ├── mod.rs │ │ │ ├── principal_manager.rs │ │ │ └── principal_utils.rs │ │ ├── cli │ │ │ ├── app.rs │ │ │ ├── mod.rs │ │ │ └── options.rs │ │ ├── common_u │ │ │ ├── errors.rs │ │ │ └── mod.rs │ │ ├── epoch_u │ │ │ ├── epoch_provider.rs │ │ │ ├── epoch_types.rs │ │ │ └── mod.rs │ │ ├── esgx │ │ │ ├── epoch_keeper_u.rs │ │ │ ├── equote.rs │ │ │ ├── general.rs │ │ │ ├── keys_keeper_u.rs │ │ │ └── mod.rs │ │ └── main.rs │ └── tests │ │ ├── evm_input_files │ │ └── input │ │ ├── principal_node │ │ ├── config │ │ │ ├── deploy_config.json │ │ │ └── principal_test_config.json │ │ └── contracts │ │ │ ├── Dummy.json │ │ │ ├── EnigmaToken.json │ │ │ ├── IEnigma.json │ │ │ └── principal_test_config.json │ │ └── quote_test.rs ├── copy_keeper_types.sh ├── enclave │ ├── Cargo.lock │ ├── Cargo.toml │ ├── Enclave.config.xml │ ├── Enclave.edl │ ├── Enclave.lds │ ├── Enclave_private.pem │ ├── Makefile │ └── src │ │ ├── epoch_keeper_t │ │ ├── epoch_t.rs │ │ ├── mod.rs │ │ └── nested_encoding.rs │ │ ├── keys_keeper_t │ │ └── mod.rs │ │ └── lib.rs ├── healthcheck.sh └── test_json_rpc.sh ├── enigma-runtime-t ├── Cargo.toml ├── src │ ├── data │ │ ├── delta.rs │ │ ├── mod.rs │ │ └── state.rs │ ├── eng_resolver.rs │ ├── gas.rs │ ├── lib.rs │ ├── ocalls_t.rs │ └── wasm_execution.rs └── tests │ └── prize.json ├── enigma-tools-m ├── Cargo.toml └── src │ ├── common │ ├── errors.rs │ ├── mod.rs │ └── utils.rs │ ├── keeper_types.rs │ ├── lib.rs │ └── primitives │ ├── km_primitives.rs │ └── mod.rs ├── enigma-tools-t ├── Cargo.toml └── src │ ├── build_arguments_g │ ├── mod.rs │ └── rlp.rs │ ├── common │ ├── errors_t.rs │ └── mod.rs │ ├── document_storage_t.rs │ ├── esgx │ ├── mod.rs │ └── ocalls_t.rs │ ├── km_primitives.rs │ ├── lib.rs │ ├── macros.rs │ ├── quote_t.rs │ └── storage_t.rs ├── enigma-tools-u ├── Cargo.toml ├── build.rs └── src │ ├── attestation_service │ ├── constants.rs │ ├── mod.rs │ └── service.rs │ ├── common_u │ ├── errors.rs │ ├── logging.rs │ ├── mod.rs │ └── os.rs │ ├── esgx │ ├── equote.rs │ ├── general.rs │ ├── mod.rs │ └── ocalls_u.rs │ ├── lib.rs │ ├── tests │ └── web3_tests │ │ ├── contracts │ │ ├── Dummy.json │ │ ├── Enigma.json │ │ └── EnigmaToken.json │ │ ├── deploy_config.json │ │ └── principal_test_config.json │ └── web3_utils │ ├── contract_ext.rs │ ├── enigma_contract.rs │ ├── mod.rs │ ├── raw_transaction.rs │ └── w3utils.rs ├── enigma-types ├── Cargo.toml ├── build.rs └── src │ ├── hash.rs │ ├── lib.rs │ ├── traits.rs │ └── types.rs ├── examples └── eng_wasm_contracts │ ├── contract_with_eth_calls │ ├── .cargo │ │ └── config │ ├── Cargo.toml │ ├── Test.json │ └── src │ │ └── lib.rs │ ├── encryption │ ├── .cargo │ │ └── config │ ├── Cargo.toml │ └── src │ │ └── lib.rs │ ├── erc20 │ ├── .cargo │ │ └── config │ ├── Cargo.toml │ └── src │ │ └── lib.rs │ ├── factorization │ ├── .cargo │ │ └── config │ ├── Cargo.toml │ └── src │ │ └── lib.rs │ ├── flip_coin │ ├── .cargo │ │ └── config │ ├── Cargo.toml │ └── src │ │ └── lib.rs │ ├── millionaires_problem_demo │ ├── .cargo │ │ └── config │ ├── Cargo.toml │ └── src │ │ └── lib.rs │ ├── simple_addition │ ├── .cargo │ │ └── config │ ├── Cargo.toml │ └── src │ │ └── lib.rs │ ├── simple_calculator │ ├── .cargo │ │ └── config │ ├── Cargo.toml │ └── src │ │ └── lib.rs │ ├── simplest │ ├── .cargo │ │ └── config │ ├── Cargo.toml │ └── src │ │ └── lib.rs │ └── voting_demo │ ├── .cargo │ └── config │ ├── Cargo.toml │ ├── VotingETH.json │ └── src │ └── lib.rs └── rust-toolchain /.dockerignore: -------------------------------------------------------------------------------- 1 | **/target 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/enigma-bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Enigma Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Backtrace** 21 | If applicable, Please paste the whole error and backtrace, if it's too long use: 22 | 23 | **Desktop (please complete the following information):** 24 | - OS: [e.g. iOS] 25 | - Version [e.g. 22] 26 | - CPU Details: [e.g. I7-7700HQ] 27 | 28 | **Additional context** 29 | Add any other context about the problem here. 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/enigma-feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Enigma Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | target/ 4 | *.wasm 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here https://doc.rust-lang.org/cargo/faq.html#why-do-binaries-have-cargolock-in-version-control-but-not-libraries 8 | Cargo.lock 9 | !*/app/Cargo.lock 10 | !*/enclave/Cargo.lock 11 | .Cargo.toml.swp 12 | 13 | # These are backup files generated by rustfmt 14 | **/*.rs.bk 15 | 16 | # SGX Files 17 | Enclave_u.c 18 | Enclave_u.h 19 | Enclave_t.c 20 | Enclave_t.h 21 | bin/ 22 | lib/ 23 | 24 | # enigma-types 25 | enigma-types.h 26 | 27 | # Prerequisites 28 | *.d 29 | 30 | # Compiled Object files 31 | *.slo 32 | *.lo 33 | *.o 34 | *.obj 35 | 36 | # Precompiled Headers 37 | *.gch 38 | *.pch 39 | 40 | # Compiled Dynamic libraries 41 | *.so 42 | *.dylib 43 | *.dll 44 | 45 | 46 | # Compiled Static libraries 47 | *.lai 48 | *.la 49 | *.a 50 | *.lib 51 | 52 | # Executables 53 | *.exe 54 | *.out 55 | *.app 56 | 57 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 58 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 59 | 60 | # CMake 61 | cmake-build-debug/ 62 | cmake-build-release/ 63 | 64 | # File-based project format 65 | *.iws 66 | 67 | # IDEs 68 | out/ 69 | .idea/ 70 | .vscode/ 71 | **/*.iml 72 | 73 | # mpeltonen/sbt-idea plugin 74 | .idea_modules/ 75 | 76 | # JIRA plugin 77 | atlassian-ide-plugin.xml 78 | 79 | # Crashlytics plugin (for Android Studio and IntelliJ) 80 | com_crashlytics_export_strings.xml 81 | crashlytics.properties 82 | crashlytics-build.properties 83 | fabric.properties 84 | 85 | # Elichai's Tests 86 | sgx-tests 87 | CMakeLists.txt 88 | dockerfile-elichai/ 89 | 90 | /target 91 | **/*.rs.bk 92 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | unstable_features = true 2 | max_width = 135 3 | comment_width = 135 4 | use_field_init_shorthand = true 5 | use_try_shorthand = true 6 | use_small_heuristics = "Max" 7 | condense_wildcard_suffixes = true 8 | fn_args_density = "Compressed" 9 | fn_single_line = true 10 | where_single_line = true 11 | merge_imports = true 12 | normalize_comments = true 13 | newline_style = "unix" 14 | brace_style = "PreferSameLine" 15 | edition = "2018" -------------------------------------------------------------------------------- /clone.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | RUN apk --update add git less openssh && \ 4 | rm -rf /var/lib/apt/lists/* && \ 5 | rm /var/cache/apk/* 6 | 7 | COPY . /enigma-core/ 8 | 9 | # use with: 10 | # docker build -f clone.Dockerfile -t gitclone_core . 11 | -------------------------------------------------------------------------------- /dockerfile/Dockerfile: -------------------------------------------------------------------------------- 1 | # inherit the baidu sdk image 2 | FROM baiduxlab/sgx-rust:1804-1.0.9 3 | 4 | LABEL maintainer=enigmampc 5 | 6 | WORKDIR /root 7 | 8 | RUN rm -rf /root/sgx 9 | 10 | # dependency for https://github.com/erickt/rust-zmq 11 | RUN apt-get update && \ 12 | apt-get install -y --no-install-recommends libzmq3-dev llvm clang-3.9 llvm-3.9-dev libclang-3.9-dev\ 13 | && rm -rf /var/lib/apt/lists/* 14 | 15 | RUN /root/.cargo/bin/rustup target add wasm32-unknown-unknown && \ 16 | /root/.cargo/bin/cargo install bindgen cargo-audit && \ 17 | rm -rf /root/.cargo/registry && rm -rf /root/.cargo/git 18 | 19 | 20 | # clone the rust-sgx-sdk baidu sdk 21 | RUN git clone --depth 1 -b v1.0.9 https://github.com/baidu/rust-sgx-sdk.git sgx 22 | 23 | 24 | RUN git clone --depth 1 --branch v5.18.3 https://github.com/facebook/rocksdb.git rocksdb && \ 25 | cd rocksdb && make install-shared -j7 && rm -rf /root/rocksdb 26 | 27 | # this is done for a run-time linker, it creates the link and cache to the installed rocksdb 28 | # (see http://man7.org/linux/man-pages/man8/ldconfig.8.html) 29 | RUN ldconfig 30 | 31 | RUN echo 'LD_LIBRARY_PATH=/opt/intel/libsgx-enclave-common/aesm /opt/intel/libsgx-enclave-common/aesm/aesm_service &' >> /root/.bashrc 32 | 33 | # Add env variable for dynamic linking of rocksdb 34 | # (see https://github.com/rust-rocksdb/rust-rocksdb/issues/217) 35 | RUN echo 'export ROCKSDB_LIB_DIR=/usr/local/lib' >> /root/.bashrc 36 | -------------------------------------------------------------------------------- /dockerfile/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | SRC=$(pwd)/../ 3 | echo "Checking your local /dev/isgx driver..." 4 | ls /dev/isgx >/dev/null 2>1 && echo -e "SGX Driver installed\n" || echo -e "SGX Driver NOT installed\n" 5 | 6 | echo -e "Removing existing enigma-core containers...\n" 7 | docker ps -a | awk '{ print $1,$2 }' | grep enigma-core | awk '{print $1 }' | xargs -I {} docker rm {} 8 | 9 | echo "Running the Docker container..." 10 | echo -e "Mapping local $SRC to container's /root/src/\n" 11 | docker run --net="host" -it -v "$SRC":/root/src:rw -v ~/.enigma:/root/.enigma:rw --device /dev/isgx --name enigma-core enigma-core 12 | -------------------------------------------------------------------------------- /eng-wasm/.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-unknown-unknown" -------------------------------------------------------------------------------- /eng-wasm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eng-wasm" 3 | version = "0.1.7" 4 | authors = ["moria "] 5 | license = "AGPL-3.0" 6 | description = "Enigma library for creating Secret Contracts" 7 | keywords = ["wasm", "webassembly", "blockchain", "sgx", "enigma"] 8 | exclude = ["derive/*"] 9 | categories = ["wasm"] 10 | 11 | [dependencies] 12 | serde_json = "1.0" 13 | serde = { version = "1.0", default-features = false } 14 | eng-pwasm-abi = "0.3" 15 | -------------------------------------------------------------------------------- /eng-wasm/derive/.rustfmt.toml: -------------------------------------------------------------------------------- 1 | # override global formatting. i want clean and standard rustfmt. 2 | -------------------------------------------------------------------------------- /eng-wasm/derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eng-wasm-derive" 3 | version = "0.1.7" 4 | authors = ["moria ", "Reuven Podmazo "] 5 | edition = "2018" 6 | license = "AGPL-3.0" 7 | description = "Enigma library for creating Secret Contracts" 8 | keywords = ["wasm", "webassembly", "blockchain", "sgx", "enigma"] 9 | categories = ["wasm"] 10 | 11 | [lib] 12 | proc-macro = true 13 | 14 | [dependencies] 15 | proc-macro2 = "1.0" 16 | syn = { version = "1.0", features = ["full"] } 17 | quote = "1.0" 18 | failure = "0.1" 19 | parse-display = "0.1" 20 | ethabi = "6.1" 21 | serde_json = "1.0" 22 | tiny-keccak = "1.4" 23 | 24 | [dev-dependencies] 25 | syn = { version = "1.0", features = ["full", "extra-traits"] } 26 | eng-wasm = { path = '..', version = "0.1" } 27 | 28 | [[example]] 29 | name = 'struct-impl' 30 | crate-type = ["cdylib"] 31 | 32 | [[example]] 33 | name = 'trait-impl' 34 | crate-type = ["cdylib"] 35 | 36 | [[example]] 37 | name = 'trait-impl-rename' 38 | crate-type = ["cdylib"] 39 | -------------------------------------------------------------------------------- /eng-wasm/derive/examples/struct-impl.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use eng_wasm_derive::pub_interface; 4 | 5 | struct MyContract; 6 | 7 | #[pub_interface] 8 | impl MyContract { 9 | /// constructor 10 | pub fn construct(_x: u32) {} 11 | 12 | /// secret contract method 13 | pub fn expand(input: u32) -> u64 { 14 | Self::expand_impl(input) 15 | } 16 | 17 | /// private method, not exported from contract 18 | fn expand_impl(input: u32) -> u64 { 19 | input as u64 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /eng-wasm/derive/examples/trait-impl-rename.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use eng_wasm_derive::pub_interface; 4 | 5 | struct MyContractImplementation; 6 | 7 | #[pub_interface(MyContractImplementation)] 8 | trait MyContract { 9 | /// constructor 10 | fn construct(_x: u32); 11 | 12 | /// secret contract method 13 | fn expand(input: u32) -> u64; 14 | } 15 | 16 | impl MyContract for MyContractImplementation { 17 | fn construct(_x: u32) {} 18 | 19 | fn expand(input: u32) -> u64 { 20 | Self::expand_impl(input) 21 | } 22 | } 23 | 24 | impl MyContractImplementation { 25 | /// private method, not exported from contract 26 | fn expand_impl(input: u32) -> u64 { 27 | input as u64 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /eng-wasm/derive/examples/trait-impl.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use eng_wasm_derive::pub_interface; 4 | 5 | struct Contract; 6 | 7 | #[pub_interface] 8 | trait MyContract { 9 | /// constructor 10 | fn construct(_x: u32); 11 | 12 | /// secret contract method 13 | fn expand(input: u32) -> u64; 14 | } 15 | 16 | impl MyContract for Contract { 17 | fn construct(_x: u32) {} 18 | 19 | fn expand(input: u32) -> u64 { 20 | Self::expand_impl(input) 21 | } 22 | } 23 | 24 | impl Contract { 25 | /// private method, not exported from contract 26 | fn expand_impl(input: u32) -> u64 { 27 | input as u64 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /eng-wasm/derive/src/eth_contract/errors.rs: -------------------------------------------------------------------------------- 1 | use failure::Fail; 2 | use std::{io, string::ToString}; 3 | use syn; 4 | 5 | #[derive(Debug, Fail)] 6 | pub enum EngWasmError { 7 | #[fail(display = "I/O error: {:?}", error)] 8 | IoError { error: String }, 9 | #[fail(display = "Json error: {}", error)] 10 | JsonError { error: String }, 11 | #[fail(display = "Token parse error: {}", error)] 12 | TokenParseError { error: String }, 13 | } 14 | 15 | impl From for EngWasmError { 16 | fn from(error: io::Error) -> Self { 17 | EngWasmError::IoError { 18 | error: error.to_string(), 19 | } 20 | } 21 | } 22 | 23 | impl From for EngWasmError { 24 | fn from(err: serde_json::Error) -> Self { 25 | EngWasmError::JsonError { 26 | error: err.to_string(), 27 | } 28 | } 29 | } 30 | 31 | impl From for EngWasmError { 32 | fn from(err: syn::parse::Error) -> Self { 33 | EngWasmError::TokenParseError { 34 | error: err.to_string(), 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /eng-wasm/derive/src/eth_contract/ethereum.rs: -------------------------------------------------------------------------------- 1 | use ethabi::param_type::{ParamType, Writer}; 2 | use tiny_keccak::Keccak; 3 | 4 | pub fn short_signature(name: &str, params: &[ParamType]) -> u32 /*[u8; 4] */ { 5 | let mut result = [0u8; 4]; 6 | fill_signature(name, params, &mut result); 7 | u32::from_be_bytes(result) 8 | } 9 | 10 | fn fill_signature(name: &str, params: &[ParamType], result: &mut [u8]) { 11 | let types = params 12 | .iter() 13 | .map(Writer::write) 14 | .collect::>() 15 | .join(","); 16 | 17 | let data: Vec = From::from(format!("{}({})", name, types).as_str()); 18 | 19 | let mut sponge = Keccak::new_keccak256(); 20 | sponge.update(&data); 21 | sponge.finalize(result); 22 | } 23 | -------------------------------------------------------------------------------- /eng-wasm/derive/src/into_ident.rs: -------------------------------------------------------------------------------- 1 | pub trait IntoIdent { 2 | fn into_ident(self) -> syn::Ident; 3 | } 4 | 5 | impl IntoIdent for &str { 6 | fn into_ident(self) -> syn::Ident { 7 | quote::format_ident!("{}", self) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /eng-wasm/derive/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(slice_concat_trait)] 2 | 3 | extern crate proc_macro; 4 | 5 | use proc_macro::TokenStream; 6 | 7 | /// This is a proc_macro2 equivalent of syn::parse_macro_input. 8 | /// 9 | /// I placed it here because [that's how macro_rules scoping works][macro-rules-scoping] 10 | /// and rust didn't like it when i put it in a module and exported it. If you figure out a 11 | /// better way to hide it, please file a PR. 12 | /// 13 | /// [macro-rules-scoping]: https://danielkeep.github.io/tlborm/book/mbe-min-scoping.html 14 | macro_rules! parse_macro_input2 { 15 | ($input: ident as $type: ty) => { 16 | match syn::parse2::<$type>($input) { 17 | Ok(parsed) => parsed, 18 | // This is what generates the diagnostics for all our error messages. 19 | Err(error) => return error.to_compile_error(), 20 | }; 21 | }; 22 | } 23 | 24 | mod into_ident; 25 | mod reduce_mut; 26 | 27 | mod eth_contract; 28 | mod pub_interface; 29 | 30 | use eth_contract::impl_eth_contract; 31 | use pub_interface::impl_pub_interface; 32 | 33 | /// This macro is used in secret contracts to define which functions they export. 34 | /// 35 | /// It can either be placed on a trait or impl block. If it is placed on a trait, 36 | /// it is expected that a struct called `Contract` implements it. All methods defined on the 37 | /// trait will be considered exported by the contract. If it is placed on an impl block, 38 | /// all methods declared as pub will be exported by the contract. if placed on an impl block, 39 | /// the implementing struct can have any name you choose. 40 | #[proc_macro_attribute] 41 | pub fn pub_interface(attr: TokenStream, item: TokenStream) -> TokenStream { 42 | impl_pub_interface(attr.into(), item.into()).into() 43 | } 44 | 45 | #[proc_macro_attribute] 46 | pub fn eth_contract(attr: TokenStream, item: TokenStream) -> TokenStream { 47 | impl_eth_contract(attr.into(), item.into()).into() 48 | } 49 | -------------------------------------------------------------------------------- /eng-wasm/derive/src/reduce_mut.rs: -------------------------------------------------------------------------------- 1 | /// This trait adds the `reduce_mut` method to all iterators. 2 | /// 3 | /// The reduce_mut method takes the first item in the iterator, and then applies the supplied 4 | /// operation on it with each subsequent item in the iterator as input. 5 | /// 6 | /// This is a slight modification of https://github.com/dtolnay/reduce 7 | /// 8 | /// We should file a pull request against dtolnay/reduce to merge this upstream. 9 | pub trait ReduceMut { 10 | fn reduce_mut(self, f: F) -> Option 11 | where 12 | Self: Sized, 13 | F: FnMut(&mut T, T); 14 | } 15 | 16 | impl ReduceMut for I 17 | where 18 | I: Iterator, 19 | { 20 | #[inline] 21 | fn reduce_mut(mut self, mut f: F) -> Option 22 | where 23 | Self: Sized, 24 | F: FnMut(&mut T, T), 25 | { 26 | self.next().map(|mut first| { 27 | for item in self { 28 | f(&mut first, item); 29 | } 30 | first 31 | }) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /eng-wasm/src/crypto_wasm.rs: -------------------------------------------------------------------------------- 1 | /// Wrapper for the Enigma runtime service for symmetric ASM-256-GCM encryption/decryption 2 | /// The encrypted text contains the IV, cyphertext, and authentication tag 3 | /// In AES-GCM the length of cyphertext is identical to the length of plain text 4 | 5 | use super::*; 6 | 7 | use eng_pwasm_abi::types::U256; 8 | use rand_wasm::Rand; 9 | 10 | const SYMMETRIC_KEY_SIZE: usize = 256 / 8; 11 | pub type SymmetricKey = [u8; SYMMETRIC_KEY_SIZE]; 12 | const AES_256_GCM_TAG_SIZE: usize = 16; 13 | const AES_256_GCM_IV_SIZE: usize = 96 / 8; 14 | 15 | 16 | /// The extra length (IV and authentication tag) of the encryption result 17 | fn extra_size_for_encrypted_text() -> usize { 18 | unsafe {AES_256_GCM_IV_SIZE + AES_256_GCM_TAG_SIZE} 19 | } 20 | 21 | 22 | pub fn generate_key() -> SymmetricKey { 23 | let key_int: U256 = Rand::gen(); 24 | let key = H256::from(key_int); 25 | key.0 26 | } 27 | 28 | pub fn encrypt(message: &[u8], key: &SymmetricKey) -> Vec { 29 | // The length of the buffer containing encrypted text 30 | let length = message.len().checked_add(extra_size_for_encrypted_text()).expect("Overflow in encrypted message length"); 31 | // The buffer containing encrypted text 32 | let mut payload = vec![0u8; length]; 33 | // Call to the runtime service to encrypt 34 | unsafe { external::encrypt(message.as_ptr(), message.len() as u32, key.as_ptr(), payload.as_mut_ptr()) }; 35 | payload 36 | } 37 | 38 | pub fn decrypt(cipheriv: &[u8], key: &SymmetricKey) -> Vec { 39 | // The length of the plaintext 40 | let length = cipheriv.len().checked_sub(extra_size_for_encrypted_text()).expect("Overflow in encrypted message length"); 41 | // The buffer for the plaintext 42 | let mut payload = vec![0u8; length]; 43 | // Call to the runtime service to decrypt 44 | unsafe { external::decrypt(cipheriv.as_ptr(), cipheriv.len() as u32, key.as_ptr(), payload.as_mut_ptr()) }; 45 | payload 46 | } 47 | -------------------------------------------------------------------------------- /eng-wasm/src/internal_std.rs: -------------------------------------------------------------------------------- 1 | pub use std::fmt; 2 | 3 | pub use std::{ 4 | io, iter, mem, 5 | slice::Join, 6 | str::from_utf8, 7 | string::{String, ToString}, 8 | vec::Vec, 9 | }; 10 | 11 | #[macro_use] 12 | pub(crate) mod std_macro { 13 | #[macro_export] 14 | macro_rules! eformat { 15 | ( $($arg:tt)* ) => ( 16 | $crate::fmt::format( format_args!($($arg)*) ) 17 | ) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /eng-wasm/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![feature(slice_concat_trait)] 3 | #![deny(unused_extern_crates)] 4 | #![allow(unused_attributes)] // TODO: Remove on future nightly https://github.com/rust-lang/rust/issues/60050 5 | 6 | /// Enigma implementation of bindings to the Enigma runtime. 7 | /// This crate should be used in contracts. 8 | #[macro_use(vec)] 9 | extern crate std; 10 | #[macro_use] 11 | extern crate serde_json; 12 | extern crate serde; 13 | #[macro_use] 14 | mod internal_std; 15 | pub mod crypto_wasm; 16 | mod rand_wasm; 17 | pub extern crate eng_pwasm_abi; 18 | 19 | pub use crypto_wasm::*; 20 | pub use eng_pwasm_abi::types::*; 21 | pub use internal_std::*; 22 | pub use rand_wasm::*; 23 | pub use serde_json::Value; 24 | 25 | pub mod external { 26 | extern "C" { 27 | pub fn write_state(key: *const u8, key_len: u32, value: *const u8, value_len: u32); 28 | pub fn read_state_len(key: *const u8, key_len: u32) -> i32; 29 | pub fn read_state(key: *const u8, key_len: u32, value_holder: *const u8); 30 | pub fn remove_from_state(key: *const u8, key_len: u32); 31 | pub fn eprint(str_ptr: *const u8, str_len: u32); 32 | pub fn fetch_function_name_length() -> i32; 33 | pub fn fetch_function_name(name_holder: *const u8); 34 | pub fn fetch_args_length() -> i32; 35 | pub fn fetch_args(name_holder: *const u8); 36 | pub fn write_eth_bridge(payload: *const u8, payload_len: u32, address: *const u8); 37 | pub fn gas(amount: u32); 38 | pub fn ret(payload: *const u8, payload_len: u32); 39 | pub fn rand(payload: *const u8, payload_len: u32); 40 | pub fn encrypt(message: *const u8, message_len: u32, key: *const u8, payload: *const u8); 41 | pub fn decrypt(cipheriv: *const u8, cipheriv_len: u32, key: *const u8, payload: *const u8); 42 | } 43 | } 44 | 45 | #[no_mangle] 46 | pub fn print(msg: &str) -> i32 { 47 | unsafe { 48 | external::eprint(msg.as_ptr(), msg.len() as u32); 49 | } 50 | 0 51 | } 52 | 53 | #[macro_export] 54 | macro_rules! eprint { 55 | ( $($arg: tt)* ) => ( 56 | $crate::print( &eformat!( $($arg)* ) ) 57 | ); 58 | } 59 | 60 | /// Write to state 61 | pub fn write(key: &str, _value: T) 62 | where T: serde::Serialize { 63 | let value = json!(_value); 64 | let value_vec = serde_json::to_vec(&value).unwrap(); 65 | unsafe { external::write_state(key.as_ptr(), key.len() as u32, value_vec.as_ptr(), value_vec.len() as u32) } 66 | } 67 | 68 | /// Read from state 69 | pub fn read(key: &str) -> Option 70 | where for<'de> T: serde::Deserialize<'de> { 71 | let val_len = unsafe { external::read_state_len(key.as_ptr(), key.len() as u32) }; 72 | let value_holder: Vec = iter::repeat(0).take(val_len as usize).collect(); 73 | unsafe { external::read_state(key.as_ptr(), key.len() as u32, value_holder.as_ptr()) }; 74 | let value: Value = serde_json::from_slice(&value_holder) 75 | .map_err(|_| print("failed unwrapping from_slice in read_state")) 76 | .expect("read_state failed"); 77 | if value.is_null() { 78 | return None; 79 | } 80 | Some( 81 | serde_json::from_value(value.clone()) 82 | .map_err(|_| print("failed unwrapping from_value in read_state")) 83 | .expect("read_state failed"), 84 | ) 85 | } 86 | 87 | /// Remove key and value from state 88 | pub fn remove(key: &str) -> Option 89 | where for<'de> T: serde::Deserialize<'de> { 90 | let value = read(key); 91 | unsafe { external::remove_from_state(key.as_ptr(), key.len() as u32) } 92 | value 93 | } 94 | 95 | pub fn write_ethereum_bridge(payload: &[u8], address: &Address) { 96 | unsafe { external::write_eth_bridge(payload.as_ptr(), payload.len() as u32, address.as_ptr()) }; 97 | } 98 | 99 | #[macro_export] 100 | macro_rules! write_state { 101 | ( $($key: expr => $val: expr),+ ) => { 102 | { 103 | $( 104 | $crate::write($key, $val); 105 | )+ 106 | } 107 | } 108 | } 109 | 110 | #[macro_export] 111 | macro_rules! read_state { 112 | ( $key: expr ) => {{ 113 | $crate::read($key) 114 | }}; 115 | } 116 | 117 | #[macro_export] 118 | macro_rules! remove_from_state { 119 | ( $key: expr ) => {{ 120 | $crate::remove($key) 121 | }}; 122 | } 123 | 124 | #[cfg(test)] 125 | mod tests { 126 | use super::*; 127 | #[test] 128 | fn what() { print("TEST!"); } 129 | 130 | #[test] 131 | fn test_encrypt() { 132 | // TODO: Is this the right place to test APIs. If so, how should we initialize the enclave? 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /eng-wasm/src/rand_wasm.rs: -------------------------------------------------------------------------------- 1 | // pub use pwasm_abi::types::*; 2 | use super::*; 3 | 4 | pub struct Rand; 5 | 6 | impl Rand { 7 | pub fn gen_slice(slice: &mut [u8]) { unsafe { external::rand(slice.as_ptr(), slice.len() as u32) }; } 8 | } 9 | 10 | pub trait RandTypes { 11 | /// generate a random number on the trusted side. 12 | fn gen() -> T; 13 | } 14 | 15 | impl RandTypes for Rand { 16 | fn gen() -> U256 { 17 | let mut r: [u8; 32] = [0u8; 32]; 18 | Self::gen_slice(&mut r); 19 | U256::from_big_endian(&r) 20 | } 21 | } 22 | 23 | impl RandTypes for Rand { 24 | fn gen() -> u8 { 25 | let mut r: [u8; 1] = [0u8; 1]; 26 | Self::gen_slice(&mut r); 27 | r[0] 28 | } 29 | } 30 | 31 | impl RandTypes for Rand { 32 | fn gen() -> u16 { 33 | let mut r: [u8; 2] = [0u8; 2]; 34 | Self::gen_slice(&mut r); 35 | u16::from_be_bytes(r) 36 | } 37 | } 38 | 39 | impl RandTypes for Rand { 40 | fn gen() -> u32 { 41 | let mut r: [u8; 4] = [0u8; 4]; 42 | Self::gen_slice(&mut r); 43 | u32::from_be_bytes(r) 44 | } 45 | } 46 | 47 | impl RandTypes for Rand { 48 | fn gen() -> u64 { 49 | let mut r: [u8; 8] = [0u8; 8]; 50 | Self::gen_slice(&mut r); 51 | u64::from_be_bytes(r) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /enigma-core/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### Version 0.3.0 2 | 3 | #### Breaking Changes 4 | 5 | * Upgrading to use Rust SGX SDK **v1.0.9** 6 | * Adding ability to revert state 7 | * `enigma-types` is now `no-std` by default. The motivation is that cargo features are almost exclusively additive, which caused unused crates to be downloaded when compiling it for `sgx`. 8 | * `gas limit` is now part of the information that is used when signing task success/failure. This allows to verify that the worker cannot (maliciously) cause task failure by giving the enclave a low `gas limit`. 9 | * changing sealing policy to `SGX_KEYPOLICY_MRSIGNER`. 10 | 11 | #### Bug Fixes 12 | 13 | * The length field in serialization of multiple values for hashing is now always a `u64` independent of the platform. 14 | * Now the state is rebuilt if it was updated by others after PTT 15 | * Storing of updated state and delta is moved to the very end of a computation, which prevents possible inconsistency. 16 | * Now the status returned by _update deltas_ depends on the individual deltas status. 17 | 18 | #### Enhancement 19 | 20 | * Adding retries for getting the attestation report from the proxy server. The number of retries may be obtained as an input, otherwise the default number is used. 21 | 22 | 23 | -------------------------------------------------------------------------------- /enigma-core/app/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "enigma-core-app" 3 | version = "0.3.0" 4 | authors = ["Enigma "] 5 | build = "build.rs" 6 | 7 | [dependencies] 8 | enigma-tools-u = {path = "../../enigma-tools-u"} 9 | enigma-tools-m = {path = "../../enigma-tools-m"} 10 | enigma-types = { path = "../../enigma-types", features = ["std"] } 11 | enigma-crypto = { path = "../../enigma-crypto" } 12 | futures = { version = "0.1.25", default-features = false } 13 | tokio-zmq = "0.9.0" 14 | zmq = "0.9.0" 15 | serde_json = "1.0" 16 | serde = { version = "1.0", default-features = false, features=["serde_derive"] } 17 | serde_repr = "0.1" 18 | rmp-serde = "0.14.0" 19 | failure = "0.1.3" 20 | rustc-hex = "1.0.0" # 2.0.1? 21 | dirs = "1.0.4" 22 | # TODO: Add compression as a feature and use it in `set_compression_type()` 23 | rocksdb = { version = "0.12.4", default-features = false } 24 | lazy_static = "1.3.0" 25 | lru-cache = "0.1.1" 26 | log = "0.4.6" 27 | log-derive = "0.3" 28 | log4rs = { version = "0.9.0", features=["all_components"]} 29 | structopt = "0.2" 30 | 31 | sgx_types = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9" } 32 | sgx_urts = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9" } 33 | 34 | [dev-dependencies] 35 | ethabi = "8.0.1" 36 | cross-test-utils = { path = "cross-test-utils" } 37 | regex = "1" 38 | rand = "0.6.5" 39 | tempfile = "3.0" 40 | itertools = "0.8" 41 | 42 | [build-dependencies] 43 | bindgen = "0.50.0" 44 | dirs = "1.0" 45 | -------------------------------------------------------------------------------- /enigma-core/app/build.rs: -------------------------------------------------------------------------------- 1 | extern crate bindgen; 2 | extern crate dirs; 3 | 4 | use std::{env, path::PathBuf}; 5 | use bindgen::{builder, EnumVariation, RustTarget}; 6 | 7 | fn main() { 8 | let sdk_dir = env::var("SGX_SDK").unwrap_or_else(|_| "/opt/sgxsdk".to_string()); 9 | let is_sim = env::var("SGX_MODE").unwrap_or_else(|_| "HW".to_string()); 10 | 11 | let rust_sgx_sdk = env::var("SGX_SDK_RUST").unwrap_or_else(|_| format!("{}/sgx", dirs::home_dir().unwrap().display())); 12 | 13 | println!("cargo:rustc-link-search=native=../lib"); 14 | println!("cargo:rustc-link-lib=static=Enclave_u"); 15 | 16 | println!("cargo:rustc-link-search=native={}/lib64", sdk_dir); 17 | match is_sim.as_ref() { 18 | "SW" => { 19 | println!("cargo:rustc-link-lib=dylib=sgx_urts_sim"); 20 | println!("cargo:rustc-link-lib=dylib=sgx_uae_service_sim"); 21 | } 22 | _ => { 23 | // Treat both HW and undefined as HW 24 | println!("cargo:rustc-link-lib=dylib=sgx_urts"); 25 | println!("cargo:rustc-link-lib=dylib=sgx_uae_service"); 26 | } 27 | } 28 | 29 | let edl = format!("{}/edl", rust_sgx_sdk); 30 | 31 | let bindings = builder() 32 | .whitelist_recursively(false) 33 | .array_pointers_in_arguments(true) 34 | .default_enum_style(EnumVariation::Rust{ non_exhaustive: false }) 35 | .rust_target(RustTarget::Nightly) 36 | .clang_arg(format!("-I{}/include", sdk_dir)) 37 | .clang_arg(format!("-I{}", edl)) 38 | .header("Enclave_u.h") 39 | .raw_line("#![allow(dead_code)]") 40 | .raw_line("use enigma_types::*;") 41 | .raw_line("use sgx_types::*;") 42 | .whitelist_function("ecall_.*") 43 | .generate() 44 | .expect("Unable to generate bindings"); 45 | 46 | let out_path = target_dir(); 47 | bindings 48 | .write_to_file(out_path.join("auto_ffi.rs")) 49 | .expect("Couldn't write bindings!"); 50 | } 51 | 52 | 53 | fn target_dir() -> PathBuf { 54 | let mut target = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); 55 | target.push("src"); 56 | target 57 | } 58 | -------------------------------------------------------------------------------- /enigma-core/app/cross-test-utils/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cross-test-utils" 3 | version = "0.3.0" 4 | authors = ["Enigma "] 5 | 6 | [dependencies] 7 | enigma-types = { path = "../../../enigma-types", features = ["std"] } 8 | enigma-crypto = { path = "../../../enigma-crypto" } 9 | futures = "0.1.25" 10 | serde_json = "1.0" 11 | serde = "1.0" 12 | serde_derive = "1.0" 13 | rmp-serde = { git = "https://github.com/3Hren/msgpack-rust.git" } # This is because of a bug of incompatibility https://github.com/3Hren/msgpack-rust/issues/189 -------------------------------------------------------------------------------- /enigma-core/app/src/auto_ffi.rs: -------------------------------------------------------------------------------- 1 | /* automatically generated by rust-bindgen */ 2 | 3 | #![allow(dead_code)] 4 | use enigma_types::*; 5 | use sgx_types::*; 6 | 7 | extern "C" { 8 | pub fn ecall_get_registration_quote( 9 | eid: sgx_enclave_id_t, 10 | retval: *mut sgx_status_t, 11 | target_info: *const sgx_target_info_t, 12 | report: *mut sgx_report_t, 13 | ) -> sgx_status_t; 14 | } 15 | extern "C" { 16 | pub fn ecall_run_tests(eid: sgx_enclave_id_t, db_ptr: *const RawPointer, result: *mut ResultStatus) -> sgx_status_t; 17 | } 18 | extern "C" { 19 | pub fn ecall_deploy( 20 | eid: sgx_enclave_id_t, 21 | retval: *mut EnclaveReturn, 22 | bytecode: *const u8, 23 | bytecode_len: usize, 24 | construct: *const u8, 25 | construct_len: usize, 26 | args: *const u8, 27 | args_len: usize, 28 | address: *const ContractAddress, 29 | user_key: *mut [u8; 64usize], 30 | gas_limit: *const u64, 31 | db_ptr: *const RawPointer, 32 | result: *mut ExecuteResult, 33 | ) -> sgx_status_t; 34 | } 35 | extern "C" { 36 | pub fn ecall_execute( 37 | eid: sgx_enclave_id_t, 38 | retval: *mut EnclaveReturn, 39 | bytecode: *const u8, 40 | bytecode_len: usize, 41 | callable: *const u8, 42 | callable_len: usize, 43 | callable_args: *const u8, 44 | callable_args_len: usize, 45 | pubkey: *mut [u8; 64usize], 46 | address: *const ContractAddress, 47 | gas_limit: *const u64, 48 | db_ptr: *const RawPointer, 49 | result: *mut ExecuteResult, 50 | ) -> sgx_status_t; 51 | } 52 | extern "C" { 53 | pub fn ecall_get_signing_address(eid: sgx_enclave_id_t, arr: *mut [u8; 20usize]) -> sgx_status_t; 54 | } 55 | extern "C" { 56 | pub fn ecall_ptt_req( 57 | eid: sgx_enclave_id_t, 58 | retval: *mut EnclaveReturn, 59 | sig: *mut [u8; 65usize], 60 | serialized_ptr: *mut u64, 61 | ) -> sgx_status_t; 62 | } 63 | extern "C" { 64 | pub fn ecall_ptt_res(eid: sgx_enclave_id_t, retval: *mut EnclaveReturn, msg_ptr: *const u8, msg_len: usize) -> sgx_status_t; 65 | } 66 | extern "C" { 67 | pub fn ecall_build_state( 68 | eid: sgx_enclave_id_t, 69 | retval: *mut EnclaveReturn, 70 | db_ptr: *const RawPointer, 71 | failed_ptr: *mut u64, 72 | ) -> sgx_status_t; 73 | } 74 | extern "C" { 75 | pub fn ecall_get_user_key( 76 | eid: sgx_enclave_id_t, 77 | retval: *mut EnclaveReturn, 78 | sig: *mut [u8; 65usize], 79 | pubkey: *mut [u8; 64usize], 80 | serialized_ptr: *mut u64, 81 | ) -> sgx_status_t; 82 | } 83 | -------------------------------------------------------------------------------- /enigma-core/app/src/cli.rs: -------------------------------------------------------------------------------- 1 | //! # Enigma Core CLI. 2 | //! 3 | //! We use `StructOpt` to easily generate the CLI https://github.com/TeXitoi/structopt
4 | //! it uses rustdocs for the `--help` menu, and proc macros to get long/short and parsing methods.
5 | //! it is used by running `let opt: Opt = Opt::from_args();` and then it will fill up the struct from the user inputs. 6 | //! (and of course fail if needed) 7 | 8 | use std::path::PathBuf; 9 | use structopt::StructOpt; 10 | 11 | #[derive(Debug, StructOpt)] 12 | #[structopt(name = "Enigma Core", about = "Enigma Core CLI commands.")] 13 | pub struct Opt { 14 | /// Specify data directory 15 | #[structopt(parse(from_os_str), long = "data-dir")] 16 | pub data_dir: Option, 17 | /// Specify a different SPID to use for the Quote/Report 18 | #[structopt(long = "spid", default_value = "B0335FD3BC1CCA8F804EB98A6420592D")] 19 | pub spid: String, 20 | /// Select a port for the enigma-p2p listener 21 | #[structopt(long = "port", short = "p", default_value = "5552")] 22 | pub port: u16, 23 | /// Specify the number of Attestation call retries when failing 24 | #[structopt(long = "retries", short = "r", default_value = "10")] 25 | pub retries: u32, 26 | /// Optional: change the minimum log level 27 | #[structopt(short = "l", long = "log-level", default_value = "info")] 28 | pub log_level: String, 29 | } -------------------------------------------------------------------------------- /enigma-core/app/src/common_u/errors.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | use sgx_types::*; 3 | use std::fmt; 4 | use failure::Error; 5 | 6 | // error while requesting to produce a quote (registration) 7 | #[derive(Fail, Debug)] 8 | #[fail(display = "Error while producing a quote sgx_status = {}. info = ({})", status, message)] 9 | pub struct ProduceQuoteErr { 10 | pub status: sgx_status_t, 11 | pub message: String, 12 | } 13 | 14 | #[derive(Fail, Debug)] 15 | #[fail(display = "Error while decoding the quote = ({})", message)] 16 | pub struct QuoteErr { 17 | pub message: String, 18 | } 19 | 20 | // error while requesting the public signing key (the registration key) 21 | #[derive(Fail, Debug)] 22 | #[fail(display = "Error while retrieving the registration signing public key sgx_status = {}. info = ({})", status, message)] 23 | pub struct GetRegisterKeyErr { 24 | pub status: sgx_status_t, 25 | pub message: String, 26 | } 27 | 28 | // error while request attestation service 29 | #[derive(Fail, Debug)] 30 | #[fail(display = "Error while using the attestation service info = ({})", message)] 31 | pub struct AttestationServiceErr { 32 | pub message: String, 33 | } 34 | 35 | #[derive(Fail, Debug)] 36 | #[fail(display = "Error while parsing the p2p messages, command: {}, error: {}", cmd, msg)] 37 | pub struct P2PErr { 38 | pub cmd: String, 39 | pub msg: String, 40 | } 41 | 42 | #[derive(Fail, Debug)] 43 | #[fail(display = "Error while trying to {}, Because: {}", command, kind)] 44 | pub struct DBErr { 45 | pub command: String, 46 | pub kind: DBErrKind, 47 | } 48 | 49 | /// This method is called by all functions removing data from the DB. checks if the error 50 | /// is of DBErr type, is so, the error is a missing key error 51 | /// (The only option for an error of that type in the delete methods) 52 | /// which is considered as a success for this matter 53 | pub fn is_db_err_type(e: Error) -> Result { 54 | e.downcast::() 55 | } 56 | 57 | #[derive(Debug)] 58 | pub enum DBErrKind { 59 | KeyExists(String), 60 | CreateError, 61 | FetchError, 62 | MissingKey(String), 63 | UpdateError, 64 | MissingKeys, 65 | } 66 | 67 | impl fmt::Display for DBErrKind { 68 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 69 | let printable: String = match &*self { 70 | DBErrKind::KeyExists(k) => format!("the key already exists for the following address: {:?}", &k), 71 | DBErrKind::CreateError => "Failed to create the key".into(), 72 | DBErrKind::FetchError => "Failed to fetch the data".into(), 73 | DBErrKind::MissingKey(k) => format!("The following Key doesn't exist: {}", &k), 74 | DBErrKind::UpdateError => "Failed to update the key".into(), 75 | DBErrKind::MissingKeys => "No keys exist the DB".into(), 76 | }; 77 | write!(f, "{}", printable) 78 | } 79 | } 80 | 81 | #[derive(Fail, Debug)] 82 | #[fail(display = "Error inside the Enclave = ({:?})", err)] 83 | pub struct EnclaveFailError { 84 | pub err: enigma_types::EnclaveReturn, 85 | pub status: sgx_status_t, 86 | } 87 | -------------------------------------------------------------------------------- /enigma-core/app/src/common_u/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod errors; 2 | -------------------------------------------------------------------------------- /enigma-core/app/src/db/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod dal; 2 | pub mod iterator; 3 | pub mod primitives; 4 | 5 | pub use crate::db::dal::*; 6 | pub use crate::db::iterator::*; 7 | pub use crate::db::primitives::*; 8 | 9 | 10 | #[cfg(test)] 11 | pub mod tests { 12 | extern crate tempfile; 13 | use self::tempfile::TempDir; 14 | use crate::db::DB; 15 | 16 | /// It's important to save TempDir too, because when it gets dropped the directory will be removed. 17 | pub fn create_test_db() -> (DB, TempDir) { 18 | let tempdir = tempfile::tempdir().unwrap(); 19 | let db = DB::new(tempdir.path(), true).unwrap(); 20 | (db, tempdir) 21 | } 22 | } -------------------------------------------------------------------------------- /enigma-core/app/src/esgx/equote.rs: -------------------------------------------------------------------------------- 1 | use common_u::errors; 2 | use failure::Error; 3 | use sgx_types::*; 4 | use std::str; 5 | use crate::auto_ffi::ecall_get_signing_address; 6 | // this struct is returned during the process registration back to the surface. 7 | // quote: the base64 encoded quote 8 | // address : the clear text public key for ecdsa signing and registration 9 | #[derive(Serialize, Deserialize, Debug)] 10 | pub struct GetRegisterResult { 11 | pub errored: bool, 12 | pub quote: String, 13 | pub address: String, 14 | } 15 | 16 | // wrapper function for getting the enclave public sign key (the one attached with produce_quote()) 17 | #[logfn(TRACE)] 18 | pub fn get_register_signing_address(eid: sgx_enclave_id_t) -> Result<[u8; 20], Error> { 19 | let mut address = [0u8; 20]; 20 | let status = unsafe { ecall_get_signing_address(eid, &mut address) }; 21 | if status == sgx_status_t::SGX_SUCCESS { 22 | Ok(address) 23 | } else { 24 | Err(errors::GetRegisterKeyErr { status, message: String::from("error in get_register_signing_key") }.into()) 25 | } 26 | } 27 | 28 | 29 | #[cfg(test)] 30 | mod test { 31 | use crate::esgx::general::init_enclave_wrapper; 32 | use enigma_tools_u::attestation_service::{self, service::AttestationService}; 33 | use enigma_tools_u::esgx::equote::retry_quote; 34 | 35 | // isans SPID = "3DDB338BD52EE314B01F1E4E1E84E8AA" 36 | // victors spid = 68A8730E9ABF1829EA3F7A66321E84D0 37 | // const SPID: &str = "1601F95C39B9EA307FEAABB901ADC3EE"; // Elichai's SPID 38 | const SPID: &str = "B0335FD3BC1CCA8F804EB98A6420592D"; // victor's SPID 39 | 40 | #[test] 41 | fn test_produce_quote() { 42 | // initiate the enclave 43 | let enclave = init_enclave_wrapper().unwrap(); 44 | // produce a quote 45 | 46 | let tested_encoded_quote = match retry_quote(enclave.geteid(), &SPID, 18) { 47 | Ok(encoded_quote) => encoded_quote, 48 | Err(e) => { 49 | println!("[-] Produce quote Err {}, {}", e.as_fail(), e.backtrace()); 50 | assert_eq!(0, 1); 51 | return; 52 | } 53 | }; 54 | println!("-------------------------"); 55 | println!("{}", tested_encoded_quote); 56 | println!("-------------------------"); 57 | enclave.destroy(); 58 | assert!(!tested_encoded_quote.is_empty()); 59 | //assert_eq!(real_encoded_quote, tested_encoded_quote); 60 | } 61 | 62 | #[test] 63 | fn test_produce_and_verify_qoute() { 64 | let enclave = init_enclave_wrapper().unwrap(); 65 | let quote = retry_quote(enclave.geteid(), &SPID, 18).unwrap(); 66 | let service = AttestationService::new(attestation_service::constants::ATTESTATION_SERVICE_URL); 67 | let as_response = service.get_report(quote).unwrap(); 68 | 69 | assert!(as_response.result.verify_report().unwrap()); 70 | } 71 | 72 | #[test] 73 | fn test_signing_key_against_quote() { 74 | let enclave = init_enclave_wrapper().unwrap(); 75 | let quote = retry_quote(enclave.geteid(), &SPID, 18).unwrap(); 76 | let service = AttestationService::new(attestation_service::constants::ATTESTATION_SERVICE_URL); 77 | let as_response = service.get_report(quote).unwrap(); 78 | assert!(as_response.result.verify_report().unwrap()); 79 | let key = super::get_register_signing_address(enclave.geteid()).unwrap(); 80 | let quote = as_response.get_quote().unwrap(); 81 | assert_eq!(key, "e.report_body.report_data[..20]); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /enigma-core/app/src/esgx/general.rs: -------------------------------------------------------------------------------- 1 | use enigma_tools_u::{self, esgx::general::storage_dir}; 2 | use sgx_types::*; 3 | use sgx_urts::SgxEnclave; 4 | use std::fs; 5 | use log; 6 | 7 | static ENCLAVE_FILE: &'static str = "../bin/enclave.signed.so"; 8 | pub static ENCLAVE_DIR: &'static str = ".enigma"; 9 | 10 | #[logfn(INFO)] 11 | pub fn init_enclave_wrapper() -> SgxResult { 12 | // Create a folder for storage (Sealed, etc) 13 | // If the storage folder is inaccessible, the enclave would not be able to seal info 14 | let storage_path = storage_dir(ENCLAVE_DIR).unwrap(); 15 | fs::create_dir_all(&storage_path).map_err(|e| { format_err!("Unable to create storage directory {}: {}", storage_path.display(), e) }).unwrap(); 16 | 17 | enigma_tools_u::esgx::init_enclave(&ENCLAVE_FILE) 18 | } 19 | -------------------------------------------------------------------------------- /enigma-core/app/src/esgx/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod equote; 2 | pub mod general; 3 | pub mod ocalls_u; 4 | -------------------------------------------------------------------------------- /enigma-core/app/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![warn(clippy::all)] 2 | #![warn(unused_extern_crates)] 3 | 4 | pub extern crate rocksdb; 5 | pub extern crate sgx_types; 6 | extern crate sgx_urts; 7 | #[macro_use] 8 | extern crate lazy_static; 9 | pub extern crate futures; 10 | extern crate rmp_serde; 11 | pub extern crate serde_json; 12 | extern crate tokio_zmq; 13 | extern crate zmq; 14 | #[macro_use] 15 | extern crate failure; 16 | pub extern crate enigma_tools_u; 17 | extern crate enigma_tools_m; 18 | extern crate enigma_crypto; 19 | extern crate enigma_types; 20 | extern crate rustc_hex as hex; 21 | extern crate lru_cache; 22 | #[macro_use] 23 | extern crate serde; 24 | extern crate serde_repr; 25 | #[macro_use] 26 | pub extern crate log; 27 | #[macro_use] 28 | pub extern crate log_derive; 29 | pub extern crate structopt; 30 | 31 | pub mod common_u; 32 | pub mod db; 33 | pub mod esgx; 34 | pub mod km_u; 35 | pub mod networking; 36 | pub mod wasm_u; 37 | pub mod cli; 38 | pub mod auto_ffi; 39 | 40 | #[cfg(feature = "cross-test-utils")] 41 | pub mod cross_test_utils { 42 | use super::*; 43 | 44 | } 45 | 46 | #[cfg(test)] 47 | mod tests { 48 | extern crate tempfile; 49 | use crate::esgx::general::init_enclave_wrapper; 50 | use sgx_types::*; 51 | use crate::db::DB; 52 | use enigma_types::{RawPointer, ResultStatus}; 53 | use enigma_tools_u::common_u::logging; 54 | use log::LevelFilter; 55 | use self::tempfile::TempDir; 56 | use crate::auto_ffi::ecall_run_tests; 57 | 58 | 59 | /// It's important to save TempDir too, because when it gets dropped the directory will be removed. 60 | fn create_test_db() -> (DB, TempDir) { 61 | let tempdir = tempfile::tempdir().unwrap(); 62 | let db = DB::new(tempdir.path(), true).unwrap(); 63 | (db, tempdir) 64 | } 65 | 66 | #[allow(dead_code)] 67 | pub fn log_to_stdout(level: Option) { 68 | let level = level.unwrap_or_else(|| LevelFilter::max()); 69 | logging::init_logger(level, ".", "Tests".to_string()).unwrap(); 70 | } 71 | 72 | #[test] 73 | pub fn test_enclave_internal() { 74 | let (mut db, _dir) = create_test_db(); 75 | let enclave = init_enclave_wrapper().unwrap(); 76 | let db_ptr = unsafe { RawPointer::new_mut(&mut db) }; 77 | let mut result: ResultStatus = ResultStatus::Ok; 78 | let ret = unsafe { ecall_run_tests(enclave.geteid(), &db_ptr as *const RawPointer, &mut result) }; 79 | 80 | assert_eq!(ret, sgx_status_t::SGX_SUCCESS); 81 | assert_eq!(result,ResultStatus::Ok); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /enigma-core/app/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate enigma_core_app; 2 | #[macro_use] 3 | extern crate log; 4 | extern crate log_derive; 5 | 6 | use log::{debug, info}; 7 | 8 | use std::str::FromStr; 9 | 10 | pub use enigma_core_app::*; 11 | pub use esgx::ocalls_u::{ocall_get_deltas, ocall_get_deltas_sizes, ocall_get_state, ocall_get_state_size, 12 | ocall_new_delta, ocall_update_state, ocall_remove_delta}; 13 | 14 | pub use enigma_tools_u::esgx::ocalls_u::{ocall_get_home, ocall_save_to_memory}; 15 | use enigma_tools_u::common_u::logging; 16 | use enigma_tools_u::common_u::os; 17 | 18 | use networking::{ipc_listener, IpcListener}; 19 | use db::DB; 20 | use cli::Opt; 21 | use structopt::StructOpt; 22 | use futures::Future; 23 | 24 | 25 | fn main() { 26 | let opt: Opt = Opt::from_args(); 27 | 28 | let log_level = log::LevelFilter::from_str(&opt.log_level).unwrap(); 29 | 30 | let datadir = opt.data_dir.clone().unwrap_or_else(|| dirs::home_dir().unwrap().join(".enigma")); 31 | let hostname = os::hostname(); 32 | let _handler = logging::init_logger(log_level, &datadir, hostname); 33 | 34 | debug!("CLI params: {:?}", opt); 35 | 36 | 37 | let enclave = esgx::general::init_enclave_wrapper().map_err(|e| {error!("Init Enclave Failed {:?}", e);}).unwrap(); 38 | let eid = enclave.geteid(); 39 | info!("Init Enclave Successful. Enclave id {}", eid); 40 | 41 | let mut db = DB::new(datadir, true).expect("Failed initializing the DB"); 42 | let server = IpcListener::new(&format!("tcp://*:{}", opt.port)); 43 | 44 | server 45 | .run(move |multi| ipc_listener::handle_message(&mut db, multi, &opt.spid, eid, opt.retries)) 46 | .wait() 47 | .unwrap(); 48 | } -------------------------------------------------------------------------------- /enigma-core/app/src/networking/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod ipc_listener; 2 | pub mod messages; 3 | 4 | pub use self::ipc_listener::IpcListener; 5 | -------------------------------------------------------------------------------- /enigma-core/app/tests/evm_input_files/input: -------------------------------------------------------------------------------- 1 | ef9fc50b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002 2 | 606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063ef9fc50b146044575b600080fd5b3415604e57600080fd5b606b60048080359060200190919080359060200190919050506081565b6040518082815260200191505060405180910390f35b600080828401905080915050929150505600a165627a7a72305820be9168caee2bd3045c4563ce44f698916986a5ad7b2148f91a35093d31d7211b0029 3 | 4 | -------------------------------------------------------------------------------- /enigma-core/app/tests/ipc_identity_and_general_tests.rs: -------------------------------------------------------------------------------- 1 | pub mod integration_utils; 2 | pub extern crate enigma_core_app as app; 3 | extern crate cross_test_utils; 4 | extern crate rustc_hex; 5 | extern crate ethabi; 6 | 7 | use integration_utils::{get_simple_msg_format, conn_and_call_ipc, is_hex, run_core, erc20_deployment_without_ptt_to_addr, 8 | run_ptt_round, contract_compute, full_simple_deployment, full_erc20_deployment}; 9 | use cross_test_utils::generate_contract_address; 10 | use rustc_hex::{ToHex, FromHex}; 11 | use std::str::from_utf8; 12 | use ethabi::Token; 13 | use app::serde_json::*; 14 | use cross_test_utils::generate_user_address; 15 | use integration_utils::enigma_crypto::symmetric; 16 | 17 | #[test] 18 | fn test_registration_params() { 19 | let port = "5570"; 20 | 21 | run_core(port); 22 | let type_req = "GetRegistrationParams"; 23 | let msg = get_simple_msg_format(type_req); 24 | let v: Value = conn_and_call_ipc(&msg.to_string(), port); 25 | 26 | let result_key = v["result"]["signingKey"].as_str().unwrap(); 27 | let result_rep= v["result"]["report"].as_str().unwrap(); 28 | let result_sig = v["result"]["signature"].as_str().unwrap(); 29 | let type_res = v["type"].as_str().unwrap(); 30 | 31 | assert_eq!(type_res, type_req); 32 | assert!(is_hex(result_key)); 33 | assert!(is_hex(result_rep)); 34 | assert!(is_hex(result_sig)); 35 | } 36 | 37 | #[test] 38 | fn test_deploy_with_no_ptt() { 39 | let port = "5575"; 40 | run_core(port); 41 | let _val = erc20_deployment_without_ptt_to_addr(port, &generate_contract_address().to_hex()); 42 | let accepted_err = _val["msg"].as_str().unwrap(); 43 | assert_eq!(accepted_err, "Error inside the Enclave = (KeysError)"); 44 | } 45 | 46 | #[test] 47 | fn test_compute_on_empty_address() { 48 | let port = "5576"; 49 | run_core(port); 50 | let _address = generate_contract_address(); 51 | let _ = run_ptt_round(port, vec![_address]); 52 | let args = [Token::FixedBytes(generate_contract_address().to_vec()), Token::Uint(100.into())]; 53 | let callable = "mint(bytes32,uint256)"; 54 | let (_val,_) = contract_compute(port, _address.into(), &args, callable); 55 | let accepted_err = _val["msg"].as_str().unwrap(); 56 | assert_eq!(accepted_err.to_string(), format!("Error while trying to get_contract, Because: The following Key doesn\'t exist: {}", _address.to_hex())); 57 | } 58 | 59 | #[test] 60 | fn test_run_ptt_twice() { 61 | let port = "5577"; 62 | run_core(port); 63 | let address = generate_contract_address(); 64 | let _val_first = run_ptt_round(port, vec![address]); 65 | let _val_second = run_ptt_round(port, vec![address]); 66 | //todo what should we expect to happen? 67 | } 68 | 69 | #[test] 70 | fn test_deploy_same_contract_twice() { 71 | let port = "5578"; 72 | run_core(port); 73 | let address = generate_contract_address(); 74 | let _val_ptt = run_ptt_round(port, vec![address]); 75 | let _deploy_first = erc20_deployment_without_ptt_to_addr(port, &address.to_hex()); 76 | let _deploy_second = erc20_deployment_without_ptt_to_addr(port, &address.to_hex()); 77 | let accepted_err = _deploy_second["msg"].as_str().unwrap(); 78 | assert_eq!(accepted_err.to_string(), format!("Error while trying to create, Because: the key already exists for the following address: {:?}", &address.to_hex())); 79 | } 80 | 81 | #[test] 82 | fn test_wrong_arguments() { 83 | let port = "5579"; 84 | run_core(port); 85 | let (_, _address) = full_simple_deployment(port); 86 | let args = [Token::FixedBytes(generate_contract_address().to_vec()), Token::FixedBytes(generate_contract_address().to_vec())]; 87 | let callable = "mint(bytes32,bytes32)"; 88 | let (val, key) = contract_compute(port, _address, &args, callable); 89 | let output = val["result"]["output"].as_str().unwrap(); 90 | let dec = symmetric::decrypt(&output.from_hex().unwrap(), &key).unwrap(); 91 | assert_eq!(from_utf8(&dec).unwrap(), "Error in execution of WASM code: unreachable"); 92 | } 93 | 94 | #[test] 95 | fn test_out_of_gas() { 96 | let port = "5580"; 97 | run_core(port); 98 | let (val, key, _) = full_erc20_deployment(port, generate_user_address().0, None, Some(200)); 99 | let output = val["result"]["output"].as_str().unwrap(); 100 | let used_gas = val["result"]["usedGas"].as_u64().unwrap(); 101 | let msg_type = val["type"].as_str().unwrap(); 102 | let dec = symmetric::decrypt(&output.from_hex().unwrap(), &key).unwrap(); 103 | assert_eq!("FailedTask", msg_type); 104 | assert_eq!("Invocation resulted in gas limit violated", from_utf8(&dec).unwrap()); 105 | assert_eq!(200, used_gas); 106 | 107 | } -------------------------------------------------------------------------------- /enigma-core/app/tests/ipc_key_exchange_tests.rs: -------------------------------------------------------------------------------- 1 | pub mod integration_utils; 2 | pub extern crate enigma_core_app as app; 3 | pub extern crate cross_test_utils; 4 | extern crate rustc_hex as hex; 5 | 6 | use integration_utils::{conn_and_call_ipc, is_hex, run_core, run_ptt_round, 7 | get_ptt_req_msg, parse_packed_msg}; 8 | use self::cross_test_utils::{generate_contract_address}; 9 | use self::app::serde_json; 10 | use app::serde_json::*; 11 | 12 | #[test] 13 | fn test_get_ptt_request() { 14 | let port = "5558"; 15 | run_core(port); 16 | 17 | let msg = get_ptt_req_msg(); 18 | let v: Value = conn_and_call_ipc(&msg.to_string(), port); 19 | 20 | let packed_msg = v["result"]["request"].as_str().unwrap(); 21 | let result_sig = v["result"]["workerSig"].as_str().unwrap(); 22 | let msg = parse_packed_msg(packed_msg); 23 | assert!(msg["data"]["Request"].is_null()); 24 | assert_eq!(msg["pubkey"].as_array().unwrap().len(), 64); 25 | assert!(is_hex(result_sig)); 26 | } 27 | 28 | #[test] 29 | fn test_ptt_response() { 30 | let port = "5559"; 31 | run_core(port); 32 | let addresses = vec![generate_contract_address(), generate_contract_address()]; 33 | let res_val: Value = run_ptt_round(port, addresses); 34 | 35 | let errors: Vec = serde_json::from_value(res_val["result"]["errors"].clone()).unwrap(); 36 | assert_eq!(errors.len(), 0); 37 | } -------------------------------------------------------------------------------- /enigma-core/enclave/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "enigma-core-enclave" 3 | version = "0.3.0" 4 | authors = ["Enigma "] 5 | 6 | [lib] 7 | name = "enigmacoreenclave" 8 | crate-type = ["staticlib"] 9 | 10 | [features] 11 | default = [] 12 | 13 | #[profile.release] 14 | #debug = true 15 | 16 | [dependencies] 17 | enigma-types = { path = "../../enigma-types", default-features = false, features = ["sgx"] } 18 | enigma-crypto = { path = "../../enigma-crypto", default-features = false, features = ["sgx", "asymmetric"] } 19 | enigma-tools-t = { path = "../../enigma-tools-t" } 20 | enigma-tools-m = { path = "../../enigma-tools-m", default-features = false, features = ["sgx"] } 21 | enigma-runtime-t = { path = "../../enigma-runtime-t" } 22 | 23 | lazy_static = {version = "1.3.0", features = ["spin_no_std"] } 24 | etcommon-hexutil = { version = "0.2", default-features = false } 25 | etcommon-bigint = { version = "0.2", default-features = false, features = ["rlp"] } 26 | rustc-hex = { version = "2.0", default-features = false } 27 | 28 | pwasm-utils = { git = "https://github.com/enigmampc/wasm-utils.git", rev = "0.5.0-sgx-1.0.9", default-features = false } 29 | parity-wasm = { git = "https://github.com/enigmampc/parity-wasm.git", branch = "enigma", default-features = false } 30 | ethabi = { git = "https://github.com/enigmampc/ethabi.git", rev = "8.0.1-sgx-1.0.9", default-features = false} 31 | error-chain = {git = "https://github.com/enigmampc/error-chain.git", rev = "0.12.0-sgx-1.0.9", default-features = false } 32 | sputnikvm-network-classic = { git = "https://github.com/enigmampc/sputnikvm.git", rev = "enigma-next", default-features = false } 33 | sputnikvm = { git = "https://github.com/enigmampc/sputnikvm.git", rev = "enigma-next", default-features = false } 34 | 35 | serde_json = { git = "https://github.com/enigmampc/serde-json-sgx.git", rev = "1.0.39-sgx-1.0.9" } 36 | wasmi = { git = "https://github.com/enigmampc/wasmi", rev = "0.4.2-sgx-1.0.9" } 37 | 38 | sgx_types = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9" } 39 | sgx_tstd = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9" } 40 | sgx_trts = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9" } 41 | sgx_tunittest = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9" } 42 | -------------------------------------------------------------------------------- /enigma-core/enclave/Enclave.config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1 4 | 0 5 | 0x40000 6 | 0x8000000 7 | 1 8 | 1 9 | 0 10 | 0 11 | 0xFFFFFFFF 12 | 13 | -------------------------------------------------------------------------------- /enigma-core/enclave/Enclave.edl: -------------------------------------------------------------------------------- 1 | enclave { 2 | from "sgx_tstd.edl" import *; 3 | from "sgx_stdio.edl" import *; 4 | from "sgx_backtrace.edl" import *; 5 | from "sgx_tstdc.edl" import *; 6 | from "sgx_fs.edl" import *; 7 | 8 | /* data structures */ 9 | include "sgx_key_exchange.h" 10 | include "enigma-types.h" 11 | trusted { 12 | 13 | public sgx_status_t ecall_get_registration_quote( 14 | [in] const sgx_target_info_t * target_info , 15 | [out] sgx_report_t * report 16 | ); 17 | 18 | public void ecall_run_tests([in] const RawPointer* db_ptr, [out] ResultStatus* result); 19 | 20 | public EnclaveReturn ecall_deploy( 21 | [in, size=bytecode_len] const uint8_t* bytecode, 22 | size_t bytecode_len, 23 | [in, size=construct_len] const uint8_t* construct, 24 | size_t construct_len, 25 | [in, count=args_len] const uint8_t* args, 26 | size_t args_len, 27 | [in] const ContractAddress* address, 28 | [in] uint8_t user_key[64], 29 | [in] const uint64_t* gas_limit, 30 | [in] const RawPointer* db_ptr, 31 | [out] ExecuteResult* result 32 | ); 33 | 34 | public EnclaveReturn ecall_execute( 35 | [in, size=bytecode_len] const uint8_t* bytecode, 36 | size_t bytecode_len, 37 | [in, size=callable_len] const uint8_t* callable, 38 | size_t callable_len, 39 | [in, size=callable_args_len] const uint8_t* callable_args, 40 | size_t callable_args_len, 41 | [in] uint8_t pubkey[64], 42 | [in] const ContractAddress* address, 43 | [in] const uint64_t* gas_limit, 44 | [in] const RawPointer* db_ptr, 45 | [out] ExecuteResult* result 46 | ); 47 | 48 | public void ecall_get_signing_address([out] uint8_t arr[20]); 49 | 50 | public EnclaveReturn ecall_ptt_req([out] uint8_t sig[65], [out] uint64_t* serialized_ptr); 51 | 52 | public EnclaveReturn ecall_ptt_res([in, size=msg_len] const uint8_t *msg_ptr, size_t msg_len); 53 | 54 | public EnclaveReturn ecall_build_state([in]const RawPointer* db_ptr, [out] uint64_t* failed_ptr); 55 | 56 | public EnclaveReturn ecall_get_user_key( 57 | [out] uint8_t sig[65], 58 | [in] uint8_t pubkey[64], 59 | [out] uint64_t* serialized_ptr 60 | ); 61 | 62 | }; 63 | untrusted { 64 | void ocall_get_home( [out, size=4096] uint8_t* output, [out] size_t* result_length); 65 | 66 | // TODO: Add explicit size wherever is possible. 67 | EnclaveReturn ocall_update_state( 68 | [in] const RawPointer* db_ptr, 69 | [in] const ContractAddress* contract_address, 70 | [in, size=len] const uint8_t* enc_state, 71 | size_t len 72 | ); 73 | 74 | EnclaveReturn ocall_new_delta( 75 | [in] const RawPointer* db_ptr, 76 | [in, size=len] const uint8_t* enc_delta, 77 | size_t len, 78 | [in] const ContractAddress* contract_address, 79 | [in] uint32_t* delta_index 80 | ); 81 | 82 | uint64_t ocall_save_to_memory([in, count=data_len] const uint8_t* data_ptr, size_t data_len); 83 | 84 | EnclaveReturn ocall_get_deltas_sizes( 85 | [in] const RawPointer* db_ptr, 86 | [in] const ContractAddress* addr, 87 | [in] const uint32_t* start, 88 | [in] const uint32_t* end, 89 | [out, count=res_len] size_t* res_ptr, 90 | size_t res_len 91 | ); 92 | 93 | EnclaveReturn ocall_get_deltas( 94 | [in] const RawPointer* db_ptr, 95 | [in] const ContractAddress* addr, 96 | [in] const uint32_t* start, 97 | [in] const uint32_t* end, 98 | [out, count=res_len] uint8_t* res_ptr, 99 | size_t res_len 100 | ); 101 | 102 | EnclaveReturn ocall_get_state_size( 103 | [in] const RawPointer* db_ptr, 104 | [in] const ContractAddress* addr, 105 | [out] size_t* state_size 106 | ); 107 | 108 | EnclaveReturn ocall_get_state( 109 | [in] const RawPointer* db_ptr, 110 | [in] const ContractAddress* addr, 111 | [out, count=state_len] uint8_t* state_pt, 112 | size_t state_len 113 | ); 114 | 115 | EnclaveReturn ocall_remove_delta( 116 | [in] const RawPointer* db_ptr, 117 | [in] const ContractAddress* contract_address, 118 | [in] uint32_t* delta_index_ 119 | ); 120 | }; 121 | }; 122 | -------------------------------------------------------------------------------- /enigma-core/enclave/Enclave.lds: -------------------------------------------------------------------------------- 1 | enclave.so 2 | { 3 | global: 4 | g_global_data_sim; 5 | g_global_data; 6 | enclave_entry; 7 | local: 8 | *; 9 | }; 10 | -------------------------------------------------------------------------------- /enigma-core/enclave/Enclave_private.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIG4gIBAAKCAYEAroOogvsj/fZDZY8XFdkl6dJmky0lRvnWMmpeH41Bla6U1qLZ 3 | AmZuyIF+mQC/cgojIsrBMzBxb1kKqzATF4+XwPwgKz7fmiddmHyYz2WDJfAjIveJ 4 | ZjdMjM4+EytGlkkJ52T8V8ds0/L2qKexJ+NBLxkeQLfV8n1mIk7zX7jguwbCG1Pr 5 | nEMdJ3Sew20vnje+RsngAzdPChoJpVsWi/K7cettX/tbnre1DL02GXc5qJoQYk7b 6 | 3zkmhz31TgFrd9VVtmUGyFXAysuSAb3EN+5VnHGr0xKkeg8utErea2FNtNIgua8H 7 | ONfm9Eiyaav1SVKzPHlyqLtcdxH3I8Wg7yqMsaprZ1n5A1v/levxnL8+It02KseD 8 | 5HqV4rf/cImSlCt3lpRg8U5E1pyFQ2IVEC/XTDMiI3c+AR+w2jSRB3Bwn9zJtFlW 9 | KHG3m1xGI4ck+Lci1JvWWLXQagQSPtZTsubxTQNx1gsgZhgv1JHVZMdbVlAbbRMC 10 | 1nSuJNl7KPAS/VfzAgEDAoIBgHRXxaynbVP5gkO0ug6Qw/E27wzIw4SmjsxG6Wpe 11 | K7kfDeRskKxESdsA/xCrKkwGwhcx1iIgS5+Qscd1Yg+1D9X9asd/P7waPmWoZd+Z 12 | AhlKwhdPsO7PiF3e1AzHhGQwsUTt/Y/aSI1MpHBvy2/s1h9mFCslOUxTmWw0oj/Q 13 | ldIEgWeNR72CE2+jFIJIyml6ftnb6qzPiga8Bm48ubKh0kvySOqnkmnPzgh+JBD6 14 | JnBmtZbfPT97bwTT+N6rnPqOOApvfHPf15kWI8yDbprG1l4OCUaIUH1AszxLd826 15 | 5IPM+8gINLRDP1MA6azECPjTyHXhtnSIBZCyWSVkc05vYmNXYUNiXWMajcxW9M02 16 | wKzFELO8NCEAkaTPxwo4SCyIjUxiK1LbQ9h8PSy4c1+gGP4LAMR8xqP4QKg6zdu9 17 | osUGG/xRe/uufgTBFkcjqBHtK5L5VI0jeNIUAgW/6iNbYXjBMJ0GfauLs+g1VsOm 18 | WfdgXzsb9DYdMa0OXXHypmV4GwKBwQDUwQj8RKJ6c8cT4vcWCoJvJF00+RFL+P3i 19 | Gx2DLERxRrDa8AVGfqaCjsR+3vLgG8V/py+z+dxZYSqeB80Qeo6PDITcRKoeAYh9 20 | xlT3LJOS+k1cJcEmlbbO2IjLkTmzSwa80fWexKu8/Xv6vv15gpqYl1ngYoqJM3pd 21 | vzmTIOi7MKSZ0WmEQavrZj8zK4endE3v0eAEeQ55j1GImbypSf7Idh7wOXtjZ7WD 22 | Dg6yWDrri+AP/L3gClMj8wsAxMV4ZR8CgcEA0fzDHkFa6raVOxWnObmRoDhAtE0a 23 | cjUj976NM5yyfdf2MrKy4/RhdTiPZ6b08/lBC/+xRfV3xKVGzacm6QjqjZrUpgHC 24 | 0LKiZaMtccCJjLtPwQd0jGQEnKfMFaPsnhOc5y8qVkCzVOSthY5qhz0XNotHHFmJ 25 | gffVgB0iqrMTvSL7IA2yqqpOqNRlhaYhNl8TiFP3gIeMtVa9rZy31JPgT2uJ+kfo 26 | gV7sdTPEjPWZd7OshGxWpT6QfVDj/T9T7L6tAoHBAI3WBf2DFvxNL2KXT2QHAZ9t 27 | k3imC4f7U+wSE6zILaDZyzygA4RUbwG0gv8/TJVn2P/Eynf76DuWHGlaiLWnCbSz 28 | Az2DHBQBBaku409zDQym3j1ugMRjzzSQWzJg0SIyBH3hTmnYcn3+Uqcp/lEBvGW6 29 | O+rsXFt3pukqJmIV8HzLGGaLm62BHUeZf3dyWm+i3p/hQAL7Xvu04QW70xuGqdr5 30 | afV7p5eaeQIJXyGQJ0eylV/90+qxjMKiB1XYg6WYvwKBwQCL/ddpgOdHJGN8uRom 31 | e7Zq0Csi3hGheMKlKbN3vcxT5U7MdyHtTZZOJbTvxKNNUNYH/8uD+PqDGNneb29G 32 | BfGzvI3EASyLIcGZF3OhKwZd0jUrWk2y7Vhob91jwp2+t73vdMbkKyI4mHOuXvGv 33 | fg95si9oO7EBT+Oqvhccd2J+F1IVXncccYnF4u5ZGWt5lLewN/pVr7MjjykeaHqN 34 | t+rfnQam2psA6fL4zS2zTmZPzR2tnY8Y1GBTi0Ko1OKd1HMCgcAb5cB/7/AQlhP9 35 | yQa04PLH9ygQkKKptZp7dy5WcWRx0K/hAHRoi2aw1wZqfm7VBNu2SLcs90kCCCxp 36 | 6C5sfJi6b8NpNbIPC+sc9wsFr7pGo9SFzQ78UlcWYK2Gu2FxlMjonhka5hvo4zvg 37 | WxlpXKEkaFt3gLd92m/dMqBrHfafH7VwOJY2zT3WIpjwuk0ZzmRg5p0pG/svVQEH 38 | NZmwRwlopysbR69B/n1nefJ84UO50fLh5s5Zr3gBRwbWNZyzhXk= 39 | -----END RSA PRIVATE KEY----- 40 | -------------------------------------------------------------------------------- /enigma-core/enclave/Makefile: -------------------------------------------------------------------------------- 1 | # Because build-dependencies and regular dependencies are mixed together it's not possible to import 2 | # bindgen into the enclave's build.rs (https://github.com/rust-lang/cargo/issues/2589) 3 | # The solution is to install the bindgen CLI in the docker and use it manually in the Makefile. 4 | 5 | SGX_SDK ?= /opt/sgxsdk 6 | 7 | Rust_Enclave_Name := libenclave.a 8 | Rust_Enclave_Files := $(wildcard src/*.rs) 9 | 10 | BINDGEN_OUTPUT_FILE := src/auto_ffi.rs 11 | BINDGEN_RAW_LINES := "\#![allow(dead_code)] use enigma_types::*; use sgx_types::*;" 12 | BINDGEN_CLANG_FLAGS := -I$(SGX_SDK)/include -I$(HOME)/sgx/edl 13 | BINDGEN_FLAGS := --default-enum-style=rust --rust-target=nightly \ 14 | --no-recursive-whitelist --use-array-pointers-in-arguments \ 15 | --whitelist-function ocall_.* --raw-line $(BINDGEN_RAW_LINES) 16 | 17 | 18 | all: bindgen $(Rust_Enclave_Name) 19 | 20 | $(Rust_Enclave_Name): $(Rust_Enclave_Files) 21 | ifeq ($(XARGO_SGX), 1) 22 | RUST_TARGET_PATH=$(shell pwd) xargo build --target x86_64-unknown-linux-sgx $(CARGO_FLAGS) 23 | cp ./target/x86_64-unknown-linux-sgx/$(Rust_target_dir)/libenigmacoreenclave.a ../lib/libenclave.a 24 | else 25 | cargo build $(CARGO_FLAGS) 26 | cp ./target/$(Rust_target_dir)/libenigmacoreenclave.a ../lib/libenclave.a 27 | endif 28 | 29 | 30 | .PHONY: bindgen 31 | bindgen: Enclave_t.h 32 | cargo build -p enigma-types $(CARGO_FLAGS) # Meant to make sure `enigma-types.h` already exists and can be included. 33 | bindgen Enclave_t.h $(BINDGEN_FLAGS) -- $(BINDGEN_CLANG_FLAGS) > $(BINDGEN_OUTPUT_FILE) 34 | rustfmt $(BINDGEN_OUTPUT_FILE) 35 | -------------------------------------------------------------------------------- /enigma-core/enclave/src/auto_ffi.rs: -------------------------------------------------------------------------------- 1 | // automatically generated by rust-bindgen 2 | 3 | #![allow(dead_code)] 4 | use enigma_types::*; 5 | use sgx_types::*; 6 | 7 | extern "C" { 8 | pub fn ocall_get_home(output: *mut u8, result_length: *mut usize) -> sgx_status_t; 9 | } 10 | extern "C" { 11 | pub fn ocall_update_state( 12 | retval: *mut EnclaveReturn, 13 | db_ptr: *const RawPointer, 14 | contract_address: *const ContractAddress, 15 | enc_state: *const u8, 16 | len: usize, 17 | ) -> sgx_status_t; 18 | } 19 | extern "C" { 20 | pub fn ocall_new_delta( 21 | retval: *mut EnclaveReturn, 22 | db_ptr: *const RawPointer, 23 | enc_delta: *const u8, 24 | len: usize, 25 | contract_address: *const ContractAddress, 26 | delta_index: *mut u32, 27 | ) -> sgx_status_t; 28 | } 29 | extern "C" { 30 | pub fn ocall_save_to_memory(retval: *mut u64, data_ptr: *const u8, data_len: usize) -> sgx_status_t; 31 | } 32 | extern "C" { 33 | pub fn ocall_get_deltas_sizes( 34 | retval: *mut EnclaveReturn, 35 | db_ptr: *const RawPointer, 36 | addr: *const ContractAddress, 37 | start: *const u32, 38 | end: *const u32, 39 | res_ptr: *mut usize, 40 | res_len: usize, 41 | ) -> sgx_status_t; 42 | } 43 | extern "C" { 44 | pub fn ocall_get_deltas( 45 | retval: *mut EnclaveReturn, 46 | db_ptr: *const RawPointer, 47 | addr: *const ContractAddress, 48 | start: *const u32, 49 | end: *const u32, 50 | res_ptr: *mut u8, 51 | res_len: usize, 52 | ) -> sgx_status_t; 53 | } 54 | extern "C" { 55 | pub fn ocall_get_state_size( 56 | retval: *mut EnclaveReturn, 57 | db_ptr: *const RawPointer, 58 | addr: *const ContractAddress, 59 | state_size: *mut usize, 60 | ) -> sgx_status_t; 61 | } 62 | extern "C" { 63 | pub fn ocall_get_state( 64 | retval: *mut EnclaveReturn, 65 | db_ptr: *const RawPointer, 66 | addr: *const ContractAddress, 67 | state_pt: *mut u8, 68 | state_len: usize, 69 | ) -> sgx_status_t; 70 | } 71 | extern "C" { 72 | pub fn ocall_remove_delta( 73 | retval: *mut EnclaveReturn, 74 | db_ptr: *const RawPointer, 75 | contract_address: *const ContractAddress, 76 | delta_index_: *mut u32, 77 | ) -> sgx_status_t; 78 | } 79 | -------------------------------------------------------------------------------- /enigma-core/enclave/src/km_t/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod principal; 2 | pub(crate) mod users; 3 | 4 | pub(crate) use self::principal::{ecall_build_state_internal, ecall_ptt_req_internal, ecall_ptt_res_internal}; 5 | pub(crate) use self::users::ecall_get_user_key_internal; 6 | 7 | use enigma_runtime_t::data::{ContractState, EncryptedContractState}; 8 | use enigma_runtime_t::ocalls_t as runtime_ocalls_t; 9 | use enigma_tools_t::common::errors_t::EnclaveError; 10 | use enigma_tools_m::utils::LockExpectMutex; 11 | use enigma_crypto::{Encryption, CryptoError}; 12 | use enigma_types::{ContractAddress, RawPointer, StateKey}; 13 | use std::collections::HashMap; 14 | use std::sync::SgxMutex; 15 | 16 | lazy_static! { 17 | pub static ref STATE_KEYS: SgxMutex> = SgxMutex::new(HashMap::new()); 18 | } 19 | 20 | pub fn get_state_key(address: ContractAddress) -> Result { 21 | let statekeys_guard = STATE_KEYS.lock_expect("State Keys"); 22 | statekeys_guard 23 | .get(&address) 24 | .copied() 25 | .ok_or_else(|| CryptoError::MissingKeyError { key_type: "State Key" }.into()) 26 | } 27 | 28 | pub fn encrypt_state(state: ContractState) -> Result, EnclaveError> { 29 | let state_keys_guard = STATE_KEYS.lock_expect("State Keys"); 30 | let key = state_keys_guard 31 | .get(&state.contract_address) 32 | .ok_or(CryptoError::MissingKeyError { key_type: "State Key" })?; 33 | state.encrypt(&key) 34 | } 35 | 36 | pub fn get_state(db_ptr: *const RawPointer, addr: ContractAddress) -> Result { 37 | let guard = STATE_KEYS.lock_expect("State Keys"); 38 | let key = guard.get(&addr).ok_or(CryptoError::MissingKeyError { key_type: "State Key" })?; 39 | 40 | let enc_state = runtime_ocalls_t::get_state(db_ptr, addr)?; 41 | let state = ContractState::decrypt(enc_state, key)?; 42 | 43 | Ok(state) 44 | } -------------------------------------------------------------------------------- /enigma-core/enclave/src/km_t/users.rs: -------------------------------------------------------------------------------- 1 | use crate::SIGNING_KEY; 2 | use enigma_tools_t::common::errors_t::EnclaveError; 3 | use enigma_tools_m::utils::LockExpectMutex; 4 | use enigma_crypto::asymmetric::KeyPair; 5 | use enigma_tools_m::primitives::km_primitives::UserMessage; 6 | use enigma_types::{DhKey, PubKey}; 7 | use std::collections::HashMap; 8 | use std::{sync::SgxMutex, vec::Vec}; 9 | 10 | lazy_static! { pub static ref DH_KEYS: SgxMutex, DhKey>> = SgxMutex::new(HashMap::new()); } 11 | 12 | pub(crate) unsafe fn ecall_get_user_key_internal(sig: &mut [u8; 65], user_pubkey: &PubKey) -> Result, EnclaveError> { 13 | let keys = KeyPair::new()?; 14 | let req = UserMessage::new(keys.get_pubkey()); 15 | *sig = SIGNING_KEY.sign(&req.to_sign())?; 16 | let msg = req.into_message()?; 17 | let enc_key = keys.derive_key(&user_pubkey)?; 18 | DH_KEYS.lock_expect("DH Keys").insert(user_pubkey.to_vec(), enc_key); 19 | Ok(msg) 20 | } 21 | -------------------------------------------------------------------------------- /enigma-crypto/Cargo.toml: -------------------------------------------------------------------------------- 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-crypto" 6 | version = "0.3.0" 7 | authors = ["Elichai Turkel "] 8 | edition = "2018" 9 | description = "A Cryptography library used for easy usage in the Enigma Protocol." 10 | 11 | [dependencies] 12 | enigma-types = { path = "../enigma-types" } 13 | rustc-hex = { version = "2.0.1", default-features = false } 14 | failure = { version = "0.1", default-features = false, features = ["derive"] } 15 | 16 | tiny-keccak = { version = "1.4", optional = true } 17 | sha2 = { version = "0.8.0", default-features = false, optional = true } 18 | libsecp256k1 = { version = "0.2", optional = true } 19 | ring = { git = "https://github.com/elichai/ring.git", rev = "sgx-0.14.6", default-features = false, optional = true } 20 | 21 | rand_std = { package = "rand", version = "0.6.4", optional = true } 22 | 23 | sgx_tstd = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9", optional = true } 24 | sgx_trts = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9", optional = true } 25 | sgx_types = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9", optional = true } 26 | 27 | 28 | # Right now symmetric encryption requires regular std or sgx std. 29 | [features] 30 | default = ["std", "symmetric", "asymmetric", "hash"] 31 | asymmetric = ["libsecp256k1", "hash"] 32 | hash = ["sha2", "tiny-keccak"] 33 | symmetric = [] 34 | # both regular std and sgx will import symmetric encryption. 35 | std = ["rand_std", "enigma-types/std", "ring/default", "symmetric"] 36 | sgx = ["sgx_trts", "sgx_tstd", "sgx_types", "enigma-types/sgx", "ring/sgx", "symmetric"] 37 | -------------------------------------------------------------------------------- /enigma-crypto/src/hash.rs: -------------------------------------------------------------------------------- 1 | //! # Hash Module 2 | //! This module provides Keccak256 and Sha256 implementations as traits for all slices. 3 | //! I think we should consider removing the Sha256 implementation to make sure we use the same hash function always. 4 | 5 | use tiny_keccak::Keccak; 6 | use enigma_types::Hash256; 7 | 8 | 9 | /// Takes a list of variables and concat them together with lengths in between. 10 | /// What this does is appends the length of the messages before each message and makes one big slice from all of them. 11 | /// e.g.: `S(H(len(a)+a, len(b)+b...))` 12 | /// # Examples 13 | /// ``` 14 | /// use enigma_crypto::hash; 15 | /// let msg = b"sign"; 16 | /// let msg2 = b"this"; 17 | /// let ready = hash::prepare_hash_multiple(&[msg, msg2]); 18 | /// ``` 19 | #[cfg(any(feature = "sgx", feature = "std"))] 20 | #[allow(unused_imports)] 21 | pub fn prepare_hash_multiple>(messages: &[B]) -> crate::localstd::vec::Vec { 22 | use crate::localstd::{vec::Vec, mem}; 23 | 24 | // The length field is always a u64. 25 | // On 16/32 bit platforms we pad the type to 64 bits. 26 | // On platforms with bigger address spaces (which don't currently exist) 27 | // we do not expect such ridiculously big slices. 28 | let length_width = mem::size_of::(); 29 | // Pre-allocate the vector once instead of reallocating as we build it. 30 | let mut res = Vec::with_capacity( 31 | // This is the exact size of the final vector. 32 | length_width * messages.len() + messages.iter().map(|message| message.as_ref().len()).sum::() 33 | ); 34 | for msg in messages { 35 | let msg = msg.as_ref(); 36 | // See wall of text above :) 37 | let len = (msg.len() as u64).to_be_bytes(); 38 | res.extend_from_slice(&len); 39 | res.extend_from_slice(&msg); 40 | } 41 | res 42 | } 43 | 44 | /// A trait that will hash using Keccak256 the object it's implemented on. 45 | pub trait Keccak256 { 46 | /// This will return a sized object with the hash 47 | fn keccak256(&self) -> T where T: Sized; 48 | } 49 | 50 | /// A trait that will hash using Sha256 the object it's implemented on. 51 | pub trait Sha256 { 52 | /// This will return a sized object with the hash 53 | fn sha256(&self) -> T where T: Sized; 54 | } 55 | 56 | impl Keccak256 for [u8] { 57 | fn keccak256(&self) -> Hash256 { 58 | let mut keccak = Keccak::new_keccak256(); 59 | let mut result = Hash256::default(); 60 | keccak.update(self); 61 | keccak.finalize(result.as_mut()); 62 | result 63 | } 64 | } 65 | 66 | impl Sha256 for [u8] { 67 | fn sha256(&self) -> Hash256 { 68 | use sha2::Digest; 69 | let mut hasher = sha2::Sha256::new(); 70 | hasher.input(&self); 71 | let mut result = Hash256::default(); 72 | result.copy_from_slice(&hasher.result()); 73 | result 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /enigma-crypto/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(all(not(feature = "std"), not(test)), no_std)] 2 | #![deny(unused_extern_crates, missing_docs, warnings)] 3 | //! # Enigma Crypto 4 | //! This library is a wrapper for all of our cryptographic needs.
5 | //! No crypto (encryption/hashing/signing etc.) should be used directly. everything should go through this library.
6 | //! This library can work on both sides of the SGX through the use of compilation cfg's.
7 | //! It also works in WASM, but without the symmetric encryption, because `ring` uses AES-NI instructions which are x86(64) only.
8 | //! 9 | //! 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. 10 | //! 11 | //! This crate is Rust 2018 Edition, 12 | //! meaning there's no `extern crate` and `use` statements need to start with `crate`/`self`/`super`. 13 | 14 | #[cfg(feature = "asymmetric")] 15 | pub mod asymmetric; 16 | #[cfg(feature = "hash")] 17 | pub mod hash; 18 | pub mod error; 19 | pub mod rand; 20 | 21 | #[cfg(feature = "symmetric")] 22 | pub mod symmetric; 23 | 24 | #[cfg(feature = "sgx")] 25 | use { 26 | sgx_tstd as localstd, 27 | }; 28 | 29 | 30 | #[cfg(feature = "std")] 31 | use { 32 | std as localstd, 33 | }; 34 | 35 | #[cfg(all(not(feature = "std"), not(feature = "sgx")))] 36 | extern crate core as localstd; 37 | 38 | pub use crate::error::CryptoError; 39 | 40 | #[cfg(feature = "asymmetric")] 41 | pub use crate::asymmetric::KeyPair; 42 | 43 | 44 | 45 | /// This trait is to encrypt/decrypt a struct, when implemented you should use `symmetric::encrypt`. 46 | /// when you implement decrypt and encrypt_with_nonce you get `encrypt` for free(don't need to implement manually). 47 | /// you should only use decrypt/encrypt. `encrypt_with_nonce` is for testing purposes only. 48 | pub trait Encryption 49 | where R: Sized, Self: Sized { 50 | /// the `encrypt` function is given for free 51 | #[allow(deprecated)] 52 | fn encrypt(self, key: T) -> Result { self.encrypt_with_nonce(key, None) } 53 | #[deprecated(note = "This function shouldn't be called directly, please use `encrypt()` instead")] 54 | /// This function is to encrypt the object using the given key. it shouldn't be used directly. 55 | /// It should only be implemented in order for you to get the normal `encrypt` function. 56 | fn encrypt_with_nonce(self, key: T, _iv: Option) -> Result; 57 | /// This function will decrypt the encrypted struct using `encrypt` into the same object. 58 | fn decrypt(enc: R, key: T) -> Result; 59 | } 60 | 61 | /// This trait is used for structures that can implement an ECDSA signing. Used to allow abstraction 62 | /// of the actual signer of the data 63 | pub trait EcdsaSign { 64 | /// This function is used to sign pre-hashed data (keccak256, or other 32-byte length hashes) 65 | fn sign_hashed(&self, to_sign: &[u8; 32]) -> [u8; 65]; 66 | } 67 | -------------------------------------------------------------------------------- /enigma-crypto/src/rand.rs: -------------------------------------------------------------------------------- 1 | //! # Rand module 2 | //! This module is an abstraction layer over the random functions.
3 | //! The purpose of it is so it can be used the same within and outside of SGX 4 | //! (through `/dev/urandom` and through the `RDRAND` instruction.) 5 | 6 | 7 | #[cfg(all(feature = "std", not(feature = "sgx")))] 8 | /// This function gets a mutable slice and will fill it 9 | /// with random data using the available randomness source 10 | pub fn random(rand: &mut [u8]) -> Result<(), crate::CryptoError> { 11 | use rand_std::{Rng, rngs::EntropyRng}; 12 | let mut rng = EntropyRng::new(); 13 | rng.try_fill(rand) 14 | .map_err(|e| crate::CryptoError::RandomError { err: e } ) 15 | } 16 | 17 | #[cfg(all(feature = "sgx", not(feature = "std")))] 18 | /// This function gets a mutable slice and will fill it 19 | /// with random data using the available randomness source 20 | pub fn random(rand: &mut [u8]) -> Result<(), crate::CryptoError> { 21 | use sgx_trts::trts::rsgx_read_rand; 22 | rsgx_read_rand(rand) 23 | .map_err(|e| crate::CryptoError::RandomError { err: e } ) 24 | } -------------------------------------------------------------------------------- /enigma-principal/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### Version 0.3.0 2 | 3 | #### Breaking Changes 4 | 5 | * Upgrading to use Rust SGX SDK **v1.0.9** 6 | * `enigma-types` is now `no-std` by default. The motivation is that cargo features are almost exclusively additive, which caused unused crates to be downloaded when compiling it for `sgx`. 7 | * Added the ability to add the configuration through environment variables 8 | * Now secret contract addresses may be obtained from Enigma contract by one call instead of two. 9 | * changing sealing policy to `SGX_KEYPOLICY_MRSIGNER`. 10 | 11 | #### Enhancement 12 | 13 | * Adding retries for getting the attestation report from the proxy server. The number of retries may be obtained as an input, otherwise the default number is used. 14 | -------------------------------------------------------------------------------- /enigma-principal/app/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "enigma-principal-app" 3 | version = "0.3.0" 4 | authors = ["Enigma "] 5 | build = "build.rs" 6 | 7 | [dependencies] 8 | enigma-types = { path = "../../enigma-types", features = ["std"] } 9 | enigma-crypto = { path = "../../enigma-crypto" } 10 | enigma-tools-u = { path = "../../enigma-tools-u" } 11 | enigma-tools-m = { path = "../../enigma-tools-m" } 12 | 13 | ethabi = "8.0.1" 14 | etcommon-rlp = "0.2" 15 | failure = "0.1.3" 16 | rustc-hex = "1.0.0" 17 | serde_json = "1.0" 18 | serde = "1.0" 19 | serde_derive = "1.0" 20 | rmp-serde = "0.13.7" 21 | structopt = "0.2.10" 22 | url = "1.7.1" 23 | colour = "0.3" 24 | dirs = "1.0" 25 | web3 = { version = "0.8", default-features = false, features=["http", "tls"] } 26 | jsonrpc-http-server = "11.0.0" 27 | log = "0.4.6" 28 | log-derive = "0.3" 29 | envy = "0.3.2" 30 | itertools = "0.8.1" 31 | secp256k1 = "0.12" 32 | sgx_types = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9" } 33 | sgx_urts = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9" } 34 | 35 | [dev-dependencies] 36 | ethereum-types = "0.6" 37 | jsonrpc-test = "11.0.0" 38 | tempfile = "3.0" 39 | -------------------------------------------------------------------------------- /enigma-principal/app/build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | fn main() { 4 | let sdk_dir = env::var("SGX_SDK").unwrap_or_else(|_| "/opt/intel/sgxsdk".to_string()); 5 | let is_sim = env::var("SGX_MODE").unwrap_or_else(|_| "HW".to_string()); 6 | 7 | println!("cargo:rustc-link-search=native=../lib"); 8 | println!("cargo:rustc-link-lib=static=Enclave_u"); 9 | 10 | println!("cargo:rustc-link-search=native={}/lib64", sdk_dir); 11 | match is_sim.as_ref() { 12 | "SW" => { 13 | println!("cargo:rustc-link-lib=dylib=sgx_urts_sim"); 14 | println!("cargo:rustc-link-lib=dylib=sgx_uae_service_sim"); 15 | } 16 | _ => { 17 | // Treat both HW and undefined as HW 18 | println!("cargo:rustc-link-lib=dylib=sgx_urts"); 19 | println!("cargo:rustc-link-lib=dylib=sgx_uae_service"); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /enigma-principal/app/src/boot_network/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "enigma_contract_path": "../app/tests/principal_node/contracts/IEnigma.json", 3 | "enigma_contract_remote_path": "", 4 | "enigma_contract_address": "cfeD223fAb2A41b5a5a5F9AaAe2D1e882cb6Fe2D", 5 | "account_address": "6330a553fc93768f612722bb8c2ec78ac90b3bbc", 6 | "test_net": true, 7 | "with_private_key": false, 8 | "private_key": "", 9 | "url": "http://localhost:9545", 10 | "epoch_size": 10, 11 | "polling_interval": 1, 12 | "max_epochs": 0, 13 | "spid": "B0335FD3BC1CCA8F804EB98A6420592D", 14 | "attestation_service_url": "https://sgx.enigma.co/api", 15 | "http_port": 3040, 16 | "confirmations": 0 17 | } 18 | -------------------------------------------------------------------------------- /enigma-principal/app/src/boot_network/deploy_scripts.rs: -------------------------------------------------------------------------------- 1 | use enigma_tools_u::web3_utils::w3utils; 2 | use failure::Error; 3 | use rustc_hex::ToHex; 4 | use std::{str, sync::Arc, thread, time}; 5 | use web3::{ 6 | contract::{Contract, Options}, 7 | futures::Future, 8 | transports::Http, 9 | types::Address, 10 | Web3, 11 | }; 12 | 13 | /// TESTING: deploy the dummy contract 14 | fn deploy_dummy_miner(w3: &Web3, deployer: &str) -> Result, Error> { 15 | // contract path 16 | let path = "../app/tests/principal_node/contracts/Dummy.json"; 17 | // build deploy params 18 | let gas_limit: u64 = 5_999_999; 19 | let poll_interval: u64 = 1; 20 | let confirmations: usize = 0; 21 | let (abi, bytecode) = w3utils::load_contract_abi_bytecode(path)?; 22 | 23 | let tx = w3utils::DeployParams::new(deployer, abi, bytecode, gas_limit, poll_interval, confirmations)?; 24 | // deploy 25 | let contract = w3utils::deploy_contract(&w3, &tx, ())?; 26 | Ok(contract) 27 | } 28 | 29 | /// TESTING: mimic block creation to test the watch blocks method of the principal node 30 | pub fn forward_blocks(w3: &Arc>, interval: u64, deployer: Address) -> Result<(), Error> { 31 | let contract = deploy_dummy_miner(&w3, &deployer.to_fixed_bytes().to_hex())?; 32 | println!("deployed dummy contract at address = {:?}", contract.address()); 33 | loop { 34 | let gas_limit: u64 = 5_999_999; 35 | let mut options = Options::default(); 36 | options.gas = Some(gas_limit.into()); 37 | // contract.call("mine",(),deployer,options ).wait().expect("error calling mine on miner."); 38 | let res = contract.call("mine", (), deployer, options).wait(); 39 | match res { 40 | Ok(_) => println!("\u{2692}"), 41 | Err(e) => println!("[-] error mining block =>{:?}", e), 42 | }; 43 | thread::sleep(time::Duration::from_secs(interval)); 44 | } 45 | } 46 | 47 | #[cfg(test)] 48 | mod test { 49 | use esgx::general::init_enclave_wrapper; 50 | use std::env; 51 | 52 | /// This function is important to enable testing both on the CI server and local. 53 | /// On the CI Side: 54 | /// The ethereum network url is being set into env variable 'NODE_URL' and taken from there. 55 | /// Anyone can modify it by simply doing $export NODE_URL= and then running the tests. 56 | /// The default is set to ganache cli "http://localhost:8545" 57 | fn get_node_url() -> String { env::var("NODE_URL").unwrap_or("http://localhost:8545".to_string()) } 58 | 59 | #[test] 60 | fn test_deploy_enigma_contract_environment() { 61 | let enclave = init_enclave_wrapper().unwrap(); 62 | let _eid = enclave.geteid(); 63 | // load the config 64 | // let deploy_config = "../app/tests/principal_node/contracts/deploy_config.json"; 65 | // let mut config = deploy_scripts::load_config(deploy_config).unwrap(); 66 | // // modify to dynamic address 67 | // config.set_ethereum_url(get_node_url()); 68 | // deploy all contracts. 69 | // let signer_addr = get_signing_address(eid).unwrap(); 70 | // let _enigma_contract = EnigmaContract::deploy_contract(Path::new(&config.enigma_token_contract_path), 71 | // Path::new(&config.enigma_contract_path), 72 | // &get_node_url(), 73 | // None, 74 | // &signer_addr).unwrap(); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /enigma-principal/app/src/boot_network/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod deploy_scripts; 2 | pub mod keys_provider_http; 3 | pub mod principal_manager; 4 | pub mod principal_utils; 5 | -------------------------------------------------------------------------------- /enigma-principal/app/src/boot_network/principal_utils.rs: -------------------------------------------------------------------------------- 1 | use std::{sync::Arc, thread, time}; 2 | 3 | use web3::{futures::Future, types::U256}; 4 | 5 | use enigma_tools_u::web3_utils::enigma_contract::EnigmaContract; 6 | use epoch_u::epoch_provider::EpochProvider; 7 | 8 | // this trait should extend the EnigmaContract into Principal specific functions. 9 | pub trait Principal { 10 | fn watch_blocks>( 11 | &self, 12 | epoch_size: usize, 13 | polling_interval: u64, 14 | epoch_provider: Arc, 15 | gas_limit: G, 16 | confirmations: usize, 17 | max_epochs: Option 18 | ); 19 | } 20 | 21 | impl Principal for EnigmaContract { 22 | /// Watches the blocks for new epoch using the epoch size and the previous epoch block number. 23 | /// For each new epoch, set the worker parameters. 24 | #[logfn(INFO)] 25 | fn watch_blocks>( 26 | &self, 27 | epoch_size: usize, 28 | polling_interval: u64, 29 | epoch_provider: Arc, 30 | gas_limit: G, 31 | confirmations: usize, 32 | max_epochs: Option 33 | ) { 34 | let gas_limit: U256 = gas_limit.into(); 35 | let max_epochs = max_epochs.unwrap_or(0); 36 | let mut epoch_counter = 0; 37 | loop { 38 | let block_number = match self.web3.eth().block_number().wait() { 39 | Ok(block_number) => block_number, 40 | Err(err) => { 41 | error!("Unable to fetch block number: {:?}", err); 42 | thread::sleep(time::Duration::from_secs(polling_interval)); 43 | continue; 44 | } 45 | }; 46 | let curr_block = block_number.low_u64() as usize; 47 | let prev_block = match epoch_provider.epoch_state_manager.last(true) { 48 | Ok(state) => state.confirmed_state.unwrap().ether_block_number, 49 | Err(_) => U256::zero(), 50 | }; 51 | let prev_block_ref = prev_block.low_u64() as usize; 52 | trace!("Blocks @ previous: {}, current: {}, next: {}", prev_block_ref, curr_block, (prev_block_ref + epoch_size)); 53 | if prev_block_ref == 0 || curr_block >= (prev_block_ref + epoch_size) { 54 | trace!("New epoch for block number {} [epoch size {}]", curr_block, epoch_size); 55 | epoch_provider 56 | .set_worker_params(block_number, gas_limit, confirmations) 57 | .expect("Unable to set worker params. Please recover manually."); 58 | } else { 59 | trace!("Epoch still active"); 60 | } 61 | thread::sleep(time::Duration::from_secs(polling_interval)); 62 | if max_epochs != 0 { 63 | // in order to avoid overflow - don't increment when max_epochs is 0 64 | epoch_counter += 1; 65 | if epoch_counter == max_epochs { 66 | error!("reached max_epochs {} , stopping.", max_epochs); 67 | break; 68 | } 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /enigma-principal/app/src/cli/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod app; 2 | pub mod options; 3 | -------------------------------------------------------------------------------- /enigma-principal/app/src/common_u/errors.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code, unused_assignments, unused_variables)] 2 | 3 | use sgx_types::*; 4 | 5 | pub const JSON_RPC_ERROR_WORKER_NOT_AUTHORIZED: i64 =-32001; 6 | pub const JSON_RPC_ERROR_ILLEGAL_STATE: i64 =-32002; 7 | 8 | // error while requesting to produce a quote (registration) 9 | #[derive(Fail, Debug)] 10 | #[fail(display = "Error while producing a quote sgx_status = {}. info = ({})", status, message)] 11 | pub struct ProduceQuoteErr { 12 | pub status: sgx_status_t, 13 | pub message: String, 14 | } 15 | 16 | // error while requesting the public signing key (the registration key) 17 | #[derive(Fail, Debug)] 18 | #[fail(display = "Error while retrieving the registration signing public key sgx_status = {}. info = ({})", status, message)] 19 | pub struct GetRegisterKeyErr { 20 | pub status: sgx_status_t, 21 | pub message: String, 22 | } 23 | 24 | // error while request attestation service 25 | #[derive(Fail, Debug)] 26 | #[fail(display = "Error while using the attestation service info = ({})", message)] 27 | pub struct AttestationServiceErr { 28 | pub message: String, 29 | } 30 | 31 | #[derive(Fail, Debug)] 32 | #[fail(display = "Error inside the Enclave = ({:?})", err)] 33 | pub struct EnclaveFailError { 34 | pub err: enigma_types::EnclaveReturn, 35 | pub status: sgx_status_t, 36 | } 37 | 38 | #[derive(Fail, Debug)] 39 | #[fail(display = "Operation not allowed while the EpochState is transitioning. Current state = {}", current_state)] 40 | pub struct EpochStateTransitionErr { 41 | pub current_state: String 42 | } 43 | 44 | #[derive(Fail, Debug)] 45 | #[fail(display = "info = ({})", message)] 46 | pub struct EpochStateIOErr { 47 | pub message: String, 48 | } 49 | 50 | #[derive(Fail, Debug)] 51 | #[fail(display = "The EpochState is undefined")] 52 | pub struct EpochStateUndefinedErr {} 53 | 54 | #[derive(Fail, Debug)] 55 | #[fail(display = "Value error in JSON-RPC request: {}. info = ({})", request, message)] 56 | pub struct RequestValueErr { 57 | pub request: String, 58 | pub message: String, 59 | } 60 | -------------------------------------------------------------------------------- /enigma-principal/app/src/common_u/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod errors; 2 | -------------------------------------------------------------------------------- /enigma-principal/app/src/epoch_u/epoch_types.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use rustc_hex::ToHex; 3 | 4 | use enigma_tools_m::keeper_types::InputWorkerParams; 5 | use ethabi::{Event, EventParam, ParamType}; 6 | use failure::Error; 7 | pub use rlp::{decode, Encodable, encode, RlpStream}; 8 | use serde::{Deserialize, Serialize}; 9 | use web3::types::{Address, Bytes, H160, U256}; 10 | 11 | use enigma_types::ContractAddress; 12 | use enigma_types::Hash256; 13 | use common_u::errors::EpochStateTransitionErr; 14 | 15 | pub const EPOCH_STATE_UNCONFIRMED: &str = "UNCONFIRMED"; 16 | pub const WORKER_PARAMETERIZED_EVENT: &str = "WorkersParameterized"; 17 | 18 | #[derive(Debug, Clone, Serialize, Deserialize)] 19 | pub struct ConfirmedEpochState { 20 | pub selected_workers: HashMap, 21 | /// The ether_block_number is the block_number which we conclude from the actual start of the epoch 22 | /// (it may differ from km_block_number due to latency issues in the network) 23 | pub ether_block_number: U256, 24 | } 25 | 26 | #[derive(Debug, Clone, Deserialize, Serialize)] 27 | pub struct EpochState { 28 | pub seed: U256, 29 | pub sig: Bytes, 30 | pub nonce: U256, 31 | /// The km_block_number is the block in which the KM decided to start a new epoch and 32 | /// the active workers are concluded from for the epoch 33 | /// (It might differ from the ether_block_number due to latency in networks) 34 | pub km_block_number: U256, 35 | pub confirmed_state: Option, 36 | } 37 | 38 | impl EpochState { 39 | pub fn new(seed: U256, sig: Bytes, nonce: U256, km_block_number: U256) -> Self { 40 | Self { seed, sig, nonce, km_block_number, confirmed_state: None } 41 | } 42 | 43 | /// Build a local mapping of smart contract address => selected worker for the epoch 44 | /// 45 | /// # Arguments 46 | /// 47 | /// * `worker_params` - The `InputWorkerParams` used to run the worker selection algorithm 48 | /// * `sc_addresses` - The Secret Contract addresses for which to retrieve the selected worker 49 | #[logfn(DEBUG)] 50 | pub fn confirm( 51 | &mut self, ether_block_number: U256, worker_params: &InputWorkerParams, sc_addresses: Vec, 52 | ) -> Result<(), Error> { 53 | info!("Confirmed epoch with worker params: {:?}", worker_params); 54 | let mut selected_workers: HashMap = HashMap::new(); 55 | for sc_address in sc_addresses { 56 | match worker_params.get_selected_worker(sc_address, self.seed) { 57 | Some(worker) => { 58 | trace!("Found selected worker: {:?} for contract: {:?}", worker, sc_address.to_hex()); 59 | match selected_workers.insert(sc_address, worker) { 60 | Some(prev) => trace!("Selected worker inserted after: {:?}", prev), 61 | None => trace!("First selected worker inserted"), 62 | } 63 | } 64 | None => { 65 | trace!("Selected worker not found for contract: {:?}", sc_address.to_hex()); 66 | } 67 | } 68 | } 69 | self.confirmed_state = Some(ConfirmedEpochState { selected_workers, ether_block_number }); 70 | Ok(()) 71 | } 72 | 73 | /// Returns the contract address that the worker is selected to work on during this epoch 74 | /// 75 | /// # Arguments 76 | /// 77 | /// * `worker` - The worker signing address 78 | #[logfn(DEBUG)] 79 | pub fn get_contract_addresses(&self, worker: &H160) -> Result, Error> { 80 | let addrs = match &self.confirmed_state { 81 | Some(state) => { 82 | let mut addrs: Vec = Vec::new(); 83 | for (&addr, account) in &state.selected_workers { 84 | if account == worker { 85 | addrs.push(addr); 86 | } 87 | } 88 | addrs 89 | } 90 | None => return Err(EpochStateTransitionErr { current_state: EPOCH_STATE_UNCONFIRMED.to_string() }.into()), 91 | }; 92 | Ok(addrs) 93 | } 94 | } 95 | 96 | #[derive(Debug, Clone)] 97 | pub struct WorkersParameterizedEvent(pub Event); 98 | 99 | impl WorkersParameterizedEvent { 100 | pub fn new() -> Self { 101 | WorkersParameterizedEvent(Event { 102 | name: WORKER_PARAMETERIZED_EVENT.to_string(), 103 | inputs: vec![ 104 | EventParam { name: "seed".to_string(), kind: ParamType::Uint(256), indexed: false }, 105 | EventParam { name: "firstBlockNumber".to_string(), kind: ParamType::Uint(256), indexed: false }, 106 | EventParam { name: "inclusionBlockNumber".to_string(), kind: ParamType::Uint(256), indexed: false }, 107 | EventParam { name: "workers".to_string(), kind: ParamType::Array(Box::new(ParamType::Address)), indexed: false }, 108 | EventParam { name: "stakes".to_string(), kind: ParamType::Array(Box::new(ParamType::Uint(256))), indexed: false }, 109 | EventParam { name: "nonce".to_string(), kind: ParamType::Uint(256), indexed: false }, 110 | ], 111 | anonymous: false, 112 | }) 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /enigma-principal/app/src/epoch_u/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod epoch_provider; 2 | pub mod epoch_types; 3 | -------------------------------------------------------------------------------- /enigma-principal/app/src/esgx/equote.rs: -------------------------------------------------------------------------------- 1 | use common_u::errors; 2 | use failure::Error; 3 | use sgx_types::*; 4 | use std::str; 5 | 6 | extern "C" { 7 | fn ecall_get_signing_address(eid: sgx_enclave_id_t, pubkey: &mut [u8; 20]) -> sgx_status_t; 8 | } 9 | extern "C" { 10 | fn ecall_get_ethereum_address(eid: sgx_enclave_id_t, pubkey: &mut [u8; 20]) -> sgx_status_t; 11 | } 12 | 13 | extern "C" { 14 | fn ecall_sign_ethereum(eid: sgx_enclave_id_t, data: &[u8; 32], sig: &mut [u8; 65]) -> sgx_status_t; 15 | } 16 | // this struct is returned during the process registration back to the surface. 17 | // quote: the base64 encoded quote 18 | // address : the clear text public key for ecdsa signing and registration 19 | #[derive(Serialize, Deserialize, Debug)] 20 | pub struct GetRegisterResult { 21 | pub errored: bool, 22 | pub quote: String, 23 | pub address: String, 24 | } 25 | 26 | // wrapper function for getting the enclave public sign key (the one attached with produce_quote()) 27 | #[logfn(TRACE)] 28 | pub fn get_register_signing_address(eid: sgx_enclave_id_t) -> Result<[u8; 20], Error> { 29 | let mut address = [0u8; 20]; 30 | let status = unsafe { ecall_get_signing_address(eid, &mut address) }; 31 | if status == sgx_status_t::SGX_SUCCESS { 32 | Ok(address) 33 | } else { 34 | Err(errors::GetRegisterKeyErr { status, message: String::from("error in get_register_signing_key") }.into()) 35 | } 36 | } 37 | 38 | // wrapper function for getting the enclave public sign key (the one attached with produce_quote()) 39 | pub fn get_ethereum_address(eid: sgx_enclave_id_t) -> Result<[u8; 20], Error> { 40 | let mut address = [0u8; 20]; 41 | let status = unsafe { ecall_get_ethereum_address(eid, &mut address) }; 42 | if status == sgx_status_t::SGX_SUCCESS { 43 | Ok(address) 44 | } else { 45 | Err(errors::GetRegisterKeyErr { status, message: String::from("error in get_ethereum_address") }.into()) 46 | } 47 | } 48 | 49 | /// wrapper function for creating a signature using the ethereum key 50 | pub fn sign_ethereum(eid: sgx_enclave_id_t, to_sign: &[u8; 32]) -> Result<[u8; 65], Error> { 51 | let mut sig = [0u8; 65]; 52 | let status = unsafe { ecall_sign_ethereum(eid,to_sign, &mut sig) }; 53 | if status == sgx_status_t::SGX_SUCCESS { 54 | Ok(sig) 55 | } else { 56 | Err(errors::GetRegisterKeyErr { status, message: String::from("error in sign_ethereum") }.into()) 57 | } 58 | } 59 | 60 | #[cfg(test)] 61 | mod test { 62 | use crate::esgx::general::init_enclave_wrapper; 63 | use enigma_tools_u::{ 64 | attestation_service::{self, service::AttestationService}, 65 | esgx::equote::retry_quote, 66 | }; 67 | 68 | // isans SPID = "3DDB338BD52EE314B01F1E4E1E84E8AA" 69 | // victors spid = 68A8730E9ABF1829EA3F7A66321E84D0 70 | const SPID: &str = "B0335FD3BC1CCA8F804EB98A6420592D"; // Elichai's SPID 71 | 72 | #[test] 73 | fn test_produce_quote() { 74 | // initiate the enclave 75 | let enclave = init_enclave_wrapper().unwrap(); 76 | // produce a quote 77 | 78 | let tested_encoded_quote = match retry_quote(enclave.geteid(), &SPID, 18) { 79 | Ok(encoded_quote) => encoded_quote, 80 | Err(e) => { 81 | println!("[-] Produce quote Err {}, {}", e.as_fail(), e.backtrace()); 82 | assert_eq!(0, 1); 83 | return; 84 | } 85 | }; 86 | println!("-------------------------"); 87 | println!("{}", tested_encoded_quote); 88 | println!("-------------------------"); 89 | enclave.destroy(); 90 | assert!(!tested_encoded_quote.is_empty()); 91 | // assert_eq!(real_encoded_quote, tested_encoded_quote); 92 | } 93 | 94 | #[test] 95 | fn test_produce_and_verify_qoute() { 96 | let enclave = init_enclave_wrapper().unwrap(); 97 | let quote = retry_quote(enclave.geteid(), &SPID, 18).unwrap(); 98 | let service = AttestationService::new(attestation_service::constants::ATTESTATION_SERVICE_URL); 99 | let as_response = service.get_report(quote).unwrap(); 100 | 101 | assert!(as_response.result.verify_report().unwrap()); 102 | } 103 | 104 | #[test] 105 | fn test_signing_key_against_quote() { 106 | let enclave = init_enclave_wrapper().unwrap(); 107 | let quote = retry_quote(enclave.geteid(), &SPID, 18).unwrap(); 108 | let service = AttestationService::new(attestation_service::constants::ATTESTATION_SERVICE_URL); 109 | let as_response = service.get_report(quote).unwrap(); 110 | assert!(as_response.result.verify_report().unwrap()); 111 | let key = super::get_register_signing_address(enclave.geteid()).unwrap(); 112 | let quote = as_response.get_quote().unwrap(); 113 | assert_eq!(key, "e.report_body.report_data[..20]); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /enigma-principal/app/src/esgx/general.rs: -------------------------------------------------------------------------------- 1 | use enigma_tools_u::{self, esgx::general::storage_dir}; 2 | use sgx_types::*; 3 | use sgx_urts::SgxEnclave; 4 | use std::{fs, path}; 5 | 6 | static ENCLAVE_FILE: &'static str = "../bin/enclave.signed.so"; 7 | pub static ENCLAVE_DIR: &'static str = ".enigma"; 8 | pub static EPOCH_DIR: &'static str = "epoch"; 9 | pub static EPOCH_FILE: &'static str = "epoch-state.msgpack"; 10 | pub static STATE_KEYS_DIR: &'static str = "state-keys"; 11 | 12 | #[logfn(INFO)] 13 | pub fn init_enclave_wrapper() -> SgxResult { 14 | // Create folders for storage (Sealed info, epoch, etc) 15 | // If the storage folders are inaccessible, km wouldn't operate properly 16 | let storage_path = storage_dir(ENCLAVE_DIR).unwrap(); 17 | fs::create_dir_all(&storage_path).map_err(|e| { format_err!("Unable to create the storage directory {}: {}", storage_path.display(), e) }).unwrap(); 18 | let epoch_storage_path = storage_path.join(EPOCH_DIR); 19 | fs::create_dir_all(&epoch_storage_path).map_err(|e| { format_err!("Unable to create the epoch storage directory {}: {}", epoch_storage_path.display(), e) }).unwrap(); 20 | let state_storage_path = storage_path.join(STATE_KEYS_DIR); 21 | fs::create_dir_all(&state_storage_path).map_err(|e| { format_err!("Unable to create the state storage directory {}: {}", state_storage_path.display(), e) }).unwrap(); 22 | 23 | enigma_tools_u::esgx::init_enclave(&ENCLAVE_FILE) 24 | } 25 | -------------------------------------------------------------------------------- /enigma-principal/app/src/esgx/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod epoch_keeper_u; 2 | pub mod equote; 3 | pub mod general; 4 | pub mod keys_keeper_u; 5 | -------------------------------------------------------------------------------- /enigma-principal/app/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(integer_atomics)] 2 | #![feature(arbitrary_self_types)] 3 | 4 | #[macro_use] 5 | extern crate colour; 6 | extern crate dirs; 7 | extern crate enigma_crypto; 8 | extern crate enigma_tools_m; 9 | extern crate enigma_tools_u; 10 | extern crate enigma_types; 11 | extern crate ethabi; 12 | #[macro_use] 13 | extern crate failure; 14 | extern crate jsonrpc_http_server; 15 | 16 | #[macro_use] 17 | extern crate log; 18 | #[macro_use] 19 | extern crate log_derive; 20 | 21 | extern crate rlp; 22 | extern crate rustc_hex; 23 | extern crate serde; 24 | #[macro_use] 25 | extern crate serde_derive; 26 | extern crate serde_json; 27 | extern crate sgx_types; 28 | extern crate sgx_urts; 29 | extern crate structopt; 30 | extern crate url; 31 | extern crate web3; 32 | extern crate rmp_serde; 33 | extern crate envy; 34 | extern crate itertools; 35 | 36 | extern crate secp256k1; 37 | 38 | 39 | use std::str::FromStr; 40 | 41 | use cli::options::Opt; 42 | use enigma_tools_u::common_u::logging; 43 | use enigma_tools_u::common_u::os; 44 | 45 | pub use enigma_tools_u::esgx::ocalls_u::{ocall_get_home, ocall_save_to_memory}; 46 | use structopt::StructOpt; 47 | 48 | // enigma modules 49 | mod boot_network; 50 | mod cli; 51 | mod common_u; 52 | mod epoch_u; 53 | mod esgx; 54 | 55 | fn main() { 56 | let opt: Opt = Opt::from_args(); 57 | 58 | let log_level = log::LevelFilter::from_str(&opt.log_level).unwrap(); 59 | let datadir = dirs::home_dir().unwrap().join(".enigma"); 60 | // let datadir = opt.data_dir.clone().unwrap_or_else(|| dirs::home_dir().unwrap().join(".enigma")); 61 | let hostname = os::hostname(); 62 | let _handler = logging::init_logger(log_level, &datadir, hostname); 63 | 64 | debug!("CLI params: {:?}", opt); 65 | 66 | let enclave = esgx::general::init_enclave_wrapper().expect("[-] Init Enclave Failed"); 67 | let eid = enclave.geteid(); 68 | cli::app::start(eid).unwrap(); 69 | info!("[+] Init Enclave Successful {}!", eid); 70 | 71 | // drop enclave when done 72 | enclave.destroy(); 73 | } 74 | 75 | #[cfg(test)] 76 | mod tests { 77 | use enigma_tools_u::common_u::logging; 78 | use esgx::general::init_enclave_wrapper; 79 | use log::LevelFilter; 80 | use sgx_types::{sgx_enclave_id_t, sgx_status_t}; 81 | use std::path::Path; 82 | 83 | extern "C" { 84 | fn ecall_run_tests(eid: sgx_enclave_id_t) -> sgx_status_t; 85 | } 86 | 87 | pub fn log_to_stdout(level: Option) { 88 | let level = level.unwrap_or_else(|| LevelFilter::max()); 89 | logging::init_logger(level, ".", "Tests".to_string()).unwrap(); 90 | } 91 | 92 | #[test] 93 | pub fn test_enclave_internal() { 94 | // initiate the enclave 95 | let enclave = match init_enclave_wrapper() { 96 | Ok(r) => { 97 | println!("[+] Init Enclave Successful {}!", r.geteid()); 98 | r 99 | } 100 | Err(x) => { 101 | println!("[-] Init Enclave Failed {}!", x.as_str()); 102 | assert_eq!(0, 1); 103 | return; 104 | } 105 | }; 106 | let ret = unsafe { ecall_run_tests(enclave.geteid()) }; 107 | assert_eq!(ret, sgx_status_t::SGX_SUCCESS); 108 | enclave.destroy(); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /enigma-principal/app/tests/evm_input_files/input: -------------------------------------------------------------------------------- 1 | ef9fc50b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002 2 | 606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063ef9fc50b146044575b600080fd5b3415604e57600080fd5b606b60048080359060200190919080359060200190919050506081565b6040518082815260200191505060405180910390f35b600080828401905080915050929150505600a165627a7a72305820be9168caee2bd3045c4563ce44f698916986a5ad7b2148f91a35093d31d7211b0029 3 | 4 | -------------------------------------------------------------------------------- /enigma-principal/app/tests/principal_node/config/deploy_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "enigma_contract_path": "../app/tests/principal_node/contracts/Enigma.json", 3 | "enigma_token_contract_path": "../app/tests/principal_node/contracts/EnigmaToken.json", 4 | "account_address": "5aeda56215b167893e80b4fe645ba6d5bab767de", 5 | "url": "http://localhost:9545" 6 | } 7 | -------------------------------------------------------------------------------- /enigma-principal/app/tests/principal_node/config/principal_test_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "enigma_contract_path": "../app/tests/principal_node/contracts/IEnigma.json", 3 | "enigma_contract_remote_path": "", 4 | "enigma_contract_address": "7beB1C37a25d099f1f1bC28929d66a4ffd2E286E", 5 | "account_address": "6330a553fc93768f612722bb8c2ec78ac90b3bbc", 6 | "test_net": true, 7 | "with_private_key": false, 8 | "private_key": "", 9 | "url": "http://localhost:9545", 10 | "epoch_size": 10, 11 | "polling_interval": 1, 12 | "max_epochs": 0, 13 | "spid": "B0335FD3BC1CCA8F804EB98A6420592D", 14 | "attestation_service_url": "https://sgx.enigma.co/api", 15 | "attestation_retries": 10, 16 | "http_port": 3040, 17 | "confirmations": 0 18 | } 19 | -------------------------------------------------------------------------------- /enigma-principal/app/tests/principal_node/contracts/principal_test_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "enigma_contract_path": "../app/tests/principal_node/contracts/Enigma.json", 3 | "enigma_contract_remote_path": "", 4 | "enigma_contract_address": "f25186B5081Ff5cE73482AD761DB0eB0d25abfBF", 5 | "account_address": "627306090abab3a6e1400e9345bc60c78a8bef57", 6 | "test_net": true, 7 | "with_private_key": false, 8 | "private_key": "", 9 | "url": "http://localhost:8545", 10 | "epoch_size": 2, 11 | "polling_interval": 1, 12 | "max_epochs": 0, 13 | "spid": "B0335FD3BC1CCA8F804EB98A6420592D", 14 | "attestation_service_url": "https://sgx.enigma.co/api" 15 | } -------------------------------------------------------------------------------- /enigma-principal/app/tests/quote_test.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /enigma-principal/copy_keeper_types.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | cp ././../enigma-tools-t/src/eth_tools_t/keeper_types_t.rs ././../enigma-tools-u/src/web3_utils/keeper_types_u.rs 3 | -------------------------------------------------------------------------------- /enigma-principal/enclave/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "enigma_principal_enclave" 3 | version = "0.3.0" 4 | authors = ["Enigma "] 5 | 6 | [lib] 7 | name = "enigma_principal_enclave" 8 | crate-type = ["staticlib"] 9 | 10 | [dependencies] 11 | enigma-tools-t = { path = "../../enigma-tools-t" } 12 | enigma-tools-m = { path = "../../enigma-tools-m", default-features = false, features = ["sgx"] } 13 | enigma-types = { path = "../../enigma-types", default-features = false, features = ["sgx"] } 14 | enigma-crypto = { path = "../../enigma-crypto", default-features = false, features = ["sgx", "asymmetric"] } 15 | 16 | lazy_static = {version = "1.3.0", features = ["spin_no_std"] } 17 | ethabi = { git = "https://github.com/enigmampc/ethabi.git", rev = "8.0.1-sgx-1.0.9", default-features = false } 18 | ethereum-types = { git = "https://github.com/enigmampc/parity-common.git", rev = "0.7.0-sgx-1.0.9", default-features = false } 19 | rustc-hex = { version = "2.0", default-features = false } 20 | 21 | sgx_types = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9" } 22 | sgx_tstd = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9" } 23 | sgx_trts = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9" } 24 | sgx_tunittest = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9" } -------------------------------------------------------------------------------- /enigma-principal/enclave/Enclave.config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 2 4 | 0 5 | 0x40000 6 | 0x100000 7 | 9 | 3 10 | 1 11 | 0 12 | 0 13 | 0xFFFFFFFF 14 | 15 | -------------------------------------------------------------------------------- /enigma-principal/enclave/Enclave.edl: -------------------------------------------------------------------------------- 1 | 2 | enclave { 3 | from "sgx_tstd.edl" import *; 4 | from "sgx_stdio.edl" import *; 5 | from "sgx_backtrace.edl" import *; 6 | from "sgx_tstdc.edl" import *; 7 | from "sgx_fs.edl" import *; 8 | 9 | /* data structures */ 10 | include "sgx_key_exchange.h" 11 | include "enigma-types.h" 12 | 13 | trusted { 14 | 15 | public sgx_status_t ecall_get_registration_quote([in] const sgx_target_info_t * target_info ,[out] sgx_report_t * report); 16 | 17 | public void ecall_run_tests(); 18 | 19 | public void ecall_get_signing_address([out] uint8_t arr[20]); 20 | 21 | public void ecall_get_ethereum_address([out] uint8_t arr[20]); 22 | 23 | public void ecall_sign_ethereum([in] uint8_t data[32], [out] uint8_t sig[65]); 24 | 25 | public EnclaveReturn ecall_set_worker_params([in, size=worker_params_rlp_len] const uint8_t* worker_params_rlp, size_t worker_params_rlp_len, 26 | [in, size=32] uint8_t* seed_in, [in, size=32] uint8_t* nonce_in, 27 | [out] uint8_t rand_out[32], [out] uint8_t nonce_out[32], 28 | [out] uint8_t sig_out[65]); 29 | 30 | public EnclaveReturn ecall_get_enc_state_keys([in, size=msg_len] const uint8_t* msg, size_t msg_len, 31 | [in, size=addrs_len] const uint8_t* addrs, size_t addrs_len, 32 | [in] uint8_t sig[65], [in, size=32] uint8_t* epoch_nonce, 33 | [out] uint64_t* serialized_ptr, [out] uint8_t sig_out[65]); 34 | }; 35 | untrusted { 36 | void ocall_get_home( [out, size=4096] uint8_t* output, [out] uint32_t* result_length); 37 | 38 | uint64_t ocall_save_to_memory( [in, count=data_len] const uint8_t* data_ptr, size_t data_len); 39 | 40 | }; 41 | }; 42 | -------------------------------------------------------------------------------- /enigma-principal/enclave/Enclave.lds: -------------------------------------------------------------------------------- 1 | enclave.so 2 | { 3 | global: 4 | g_global_data_sim; 5 | g_global_data; 6 | enclave_entry; 7 | local: 8 | *; 9 | }; 10 | -------------------------------------------------------------------------------- /enigma-principal/enclave/Enclave_private.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIG4gIBAAKCAYEAroOogvsj/fZDZY8XFdkl6dJmky0lRvnWMmpeH41Bla6U1qLZ 3 | AmZuyIF+mQC/cgojIsrBMzBxb1kKqzATF4+XwPwgKz7fmiddmHyYz2WDJfAjIveJ 4 | ZjdMjM4+EytGlkkJ52T8V8ds0/L2qKexJ+NBLxkeQLfV8n1mIk7zX7jguwbCG1Pr 5 | nEMdJ3Sew20vnje+RsngAzdPChoJpVsWi/K7cettX/tbnre1DL02GXc5qJoQYk7b 6 | 3zkmhz31TgFrd9VVtmUGyFXAysuSAb3EN+5VnHGr0xKkeg8utErea2FNtNIgua8H 7 | ONfm9Eiyaav1SVKzPHlyqLtcdxH3I8Wg7yqMsaprZ1n5A1v/levxnL8+It02KseD 8 | 5HqV4rf/cImSlCt3lpRg8U5E1pyFQ2IVEC/XTDMiI3c+AR+w2jSRB3Bwn9zJtFlW 9 | KHG3m1xGI4ck+Lci1JvWWLXQagQSPtZTsubxTQNx1gsgZhgv1JHVZMdbVlAbbRMC 10 | 1nSuJNl7KPAS/VfzAgEDAoIBgHRXxaynbVP5gkO0ug6Qw/E27wzIw4SmjsxG6Wpe 11 | K7kfDeRskKxESdsA/xCrKkwGwhcx1iIgS5+Qscd1Yg+1D9X9asd/P7waPmWoZd+Z 12 | AhlKwhdPsO7PiF3e1AzHhGQwsUTt/Y/aSI1MpHBvy2/s1h9mFCslOUxTmWw0oj/Q 13 | ldIEgWeNR72CE2+jFIJIyml6ftnb6qzPiga8Bm48ubKh0kvySOqnkmnPzgh+JBD6 14 | JnBmtZbfPT97bwTT+N6rnPqOOApvfHPf15kWI8yDbprG1l4OCUaIUH1AszxLd826 15 | 5IPM+8gINLRDP1MA6azECPjTyHXhtnSIBZCyWSVkc05vYmNXYUNiXWMajcxW9M02 16 | wKzFELO8NCEAkaTPxwo4SCyIjUxiK1LbQ9h8PSy4c1+gGP4LAMR8xqP4QKg6zdu9 17 | osUGG/xRe/uufgTBFkcjqBHtK5L5VI0jeNIUAgW/6iNbYXjBMJ0GfauLs+g1VsOm 18 | WfdgXzsb9DYdMa0OXXHypmV4GwKBwQDUwQj8RKJ6c8cT4vcWCoJvJF00+RFL+P3i 19 | Gx2DLERxRrDa8AVGfqaCjsR+3vLgG8V/py+z+dxZYSqeB80Qeo6PDITcRKoeAYh9 20 | xlT3LJOS+k1cJcEmlbbO2IjLkTmzSwa80fWexKu8/Xv6vv15gpqYl1ngYoqJM3pd 21 | vzmTIOi7MKSZ0WmEQavrZj8zK4endE3v0eAEeQ55j1GImbypSf7Idh7wOXtjZ7WD 22 | Dg6yWDrri+AP/L3gClMj8wsAxMV4ZR8CgcEA0fzDHkFa6raVOxWnObmRoDhAtE0a 23 | cjUj976NM5yyfdf2MrKy4/RhdTiPZ6b08/lBC/+xRfV3xKVGzacm6QjqjZrUpgHC 24 | 0LKiZaMtccCJjLtPwQd0jGQEnKfMFaPsnhOc5y8qVkCzVOSthY5qhz0XNotHHFmJ 25 | gffVgB0iqrMTvSL7IA2yqqpOqNRlhaYhNl8TiFP3gIeMtVa9rZy31JPgT2uJ+kfo 26 | gV7sdTPEjPWZd7OshGxWpT6QfVDj/T9T7L6tAoHBAI3WBf2DFvxNL2KXT2QHAZ9t 27 | k3imC4f7U+wSE6zILaDZyzygA4RUbwG0gv8/TJVn2P/Eynf76DuWHGlaiLWnCbSz 28 | Az2DHBQBBaku409zDQym3j1ugMRjzzSQWzJg0SIyBH3hTmnYcn3+Uqcp/lEBvGW6 29 | O+rsXFt3pukqJmIV8HzLGGaLm62BHUeZf3dyWm+i3p/hQAL7Xvu04QW70xuGqdr5 30 | afV7p5eaeQIJXyGQJ0eylV/90+qxjMKiB1XYg6WYvwKBwQCL/ddpgOdHJGN8uRom 31 | e7Zq0Csi3hGheMKlKbN3vcxT5U7MdyHtTZZOJbTvxKNNUNYH/8uD+PqDGNneb29G 32 | BfGzvI3EASyLIcGZF3OhKwZd0jUrWk2y7Vhob91jwp2+t73vdMbkKyI4mHOuXvGv 33 | fg95si9oO7EBT+Oqvhccd2J+F1IVXncccYnF4u5ZGWt5lLewN/pVr7MjjykeaHqN 34 | t+rfnQam2psA6fL4zS2zTmZPzR2tnY8Y1GBTi0Ko1OKd1HMCgcAb5cB/7/AQlhP9 35 | yQa04PLH9ygQkKKptZp7dy5WcWRx0K/hAHRoi2aw1wZqfm7VBNu2SLcs90kCCCxp 36 | 6C5sfJi6b8NpNbIPC+sc9wsFr7pGo9SFzQ78UlcWYK2Gu2FxlMjonhka5hvo4zvg 37 | WxlpXKEkaFt3gLd92m/dMqBrHfafH7VwOJY2zT3WIpjwuk0ZzmRg5p0pG/svVQEH 38 | NZmwRwlopysbR69B/n1nefJ84UO50fLh5s5Zr3gBRwbWNZyzhXk= 39 | -----END RSA PRIVATE KEY----- 40 | -------------------------------------------------------------------------------- /enigma-principal/enclave/Makefile: -------------------------------------------------------------------------------- 1 | 2 | Rust_Enclave_Name := libenclave.a 3 | Rust_Enclave_Files := $(wildcard src/*.rs) 4 | 5 | .PHONY: all 6 | 7 | all: $(Rust_Enclave_Name) 8 | 9 | $(Rust_Enclave_Name): $(Rust_Enclave_Files) 10 | ifeq ($(XARGO_SGX), 1) 11 | RUST_TARGET_PATH=$(shell pwd) xargo build --target x86_64-unknown-linux-sgx $(CARGO_FLAGS) 12 | cp ./target/x86_64-unknown-linux-sgx/$(Rust_target_dir)/libenigmacoreenclave.a ../lib/libenclave.a 13 | else 14 | cargo build $(CARGO_FLAGS) 15 | cp ./target/$(Rust_target_dir)/libenigma_principal_enclave.a ../lib/libenclave.a 16 | endif -------------------------------------------------------------------------------- /enigma-principal/enclave/src/epoch_keeper_t/epoch_t.rs: -------------------------------------------------------------------------------- 1 | use enigma_tools_m::keeper_types::{InputWorkerParams, RawEncodable}; 2 | use ethabi::Bytes; 3 | use ethereum_types::{H160, H256, U256, BigEndianHash}; 4 | use std::string::ToString; 5 | use std::vec::Vec; 6 | 7 | use enigma_tools_t::common::errors_t::{ 8 | EnclaveError::{self, SystemError}, 9 | EnclaveSystemError, 10 | }; 11 | use enigma_types::ContractAddress; 12 | use super::nested_encoding::NestedSerialization; 13 | 14 | pub type EpochNonce = [u8; 32]; 15 | pub type EpochMarker = [u8; 64]; 16 | 17 | #[derive(Debug, Clone)] 18 | pub struct Epoch { 19 | pub nonce: U256, 20 | pub seed: U256, 21 | pub worker_params: InputWorkerParams, 22 | } 23 | 24 | impl Epoch { 25 | pub fn get_selected_worker(&self, sc_addr: ContractAddress) -> Result { 26 | self.worker_params 27 | .get_selected_worker(sc_addr, self.seed) 28 | .ok_or_else(|| SystemError(EnclaveSystemError::WorkerAuthError { err: "Worker selection returns nothing.".to_string() })) 29 | } 30 | 31 | pub fn encode_for_hashing(&self) -> Bytes { 32 | let mut encoding: Vec = Vec::new(); 33 | 34 | let seed_encoding = self.seed.hash_encode(); 35 | let nonce_encoding = self.nonce.hash_encode(); 36 | let workers_encoding = self.worker_params.workers.hash_encode(); 37 | let stakes_encoding = self.worker_params.stakes.hash_encode(); 38 | 39 | encoding.extend_from_slice(&seed_encoding); 40 | encoding.extend_from_slice(&nonce_encoding); 41 | encoding.extend_from_slice(&workers_encoding); 42 | encoding.extend_from_slice(&stakes_encoding); 43 | 44 | encoding 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /enigma-principal/enclave/src/epoch_keeper_t/nested_encoding.rs: -------------------------------------------------------------------------------- 1 | use std::vec::Vec; 2 | use ethereum_types::{U256,H160}; 3 | 4 | pub const ONE: u8 = 1; 5 | pub const ZERO: u8 = 0; 6 | /// implements the serialization for types needed for epoch encoding in the KM node, 7 | /// according to this proof: https://github.com/enigmampc/protocol-discovery/blob/master/docs/hash_mul_nested.pdf 8 | pub trait NestedSerialization { 9 | fn hash_encode(&self) -> Vec; 10 | } 11 | 12 | impl NestedSerialization for U256 { 13 | fn hash_encode(&self) -> Vec { 14 | let mut res: Vec = Vec::new(); 15 | let mut msg = [0u8;32]; 16 | 17 | self.to_big_endian(&mut msg); 18 | let len = (msg.len() as u64).to_be_bytes(); 19 | 20 | res.push(ZERO); 21 | res.extend_from_slice(&len); 22 | res.extend_from_slice(&msg); 23 | res 24 | } 25 | } 26 | 27 | impl NestedSerialization for H160 { 28 | fn hash_encode(&self) -> Vec { 29 | let mut res: Vec = Vec::new(); 30 | let msg: &[u8] = self.as_ref(); 31 | let len = (msg.len() as u64).to_be_bytes(); 32 | 33 | res.push(ZERO); 34 | res.extend_from_slice(&len); 35 | res.extend_from_slice(&msg); 36 | res 37 | } 38 | } 39 | 40 | impl NestedSerialization for Vec { 41 | fn hash_encode(&self) -> Vec { 42 | let mut res: Vec = Vec::new(); 43 | let mut messages = Vec::new(); 44 | let mut res_len: usize = 0; 45 | 46 | for value in self.iter() { 47 | let msg = value.hash_encode(); 48 | res_len += msg.len(); 49 | messages.extend_from_slice(&msg); 50 | } 51 | 52 | let final_len = (res_len as u64).to_be_bytes(); 53 | res.push(ONE); 54 | res.extend_from_slice(&final_len); 55 | res.extend_from_slice(&messages); 56 | res 57 | } 58 | } 59 | 60 | pub mod tests { 61 | use ethereum_types::{H160, U256}; 62 | 63 | use super::*; 64 | 65 | pub fn test_u256_nested() { 66 | let expected_arr : Vec = vec![0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24]; 67 | let num = U256::from(24); 68 | let accepted_arr = num.hash_encode(); 69 | assert_eq!(expected_arr, accepted_arr); 70 | } 71 | 72 | pub fn test_h160_nested() { 73 | let expected_arr : Vec = vec![0, 0, 0, 0, 0, 0, 0, 0, 20, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]; 74 | let addr = H160::from([2u8; 20]); 75 | let accepted_arr = addr.hash_encode(); 76 | assert_eq!(expected_arr, accepted_arr); 77 | } 78 | 79 | pub fn test_vec_u256_nested() { 80 | let expected_arr = vec![1, 0, 0, 0, 0, 0, 0, 0, 164, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 194, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 243, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 140, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 232]; 81 | let vec_nums: Vec = vec![U256::from(2498), U256::from(243), U256::from(2444), U256::from(21224)]; 82 | let accepted_arr = vec_nums.hash_encode(); 83 | assert_eq!(expected_arr, accepted_arr); 84 | } 85 | 86 | pub fn test_double_nested_vec_h160() { 87 | let expected_arr = vec![1, 0, 0, 0, 0, 0, 0, 0, 125, 1, 0, 0, 0, 0, 0, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 20, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 20, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 0, 0, 0, 0, 0, 0, 0, 0, 20, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 20, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231]; 88 | let vec_vec_addr: Vec> = vec![vec![H160::from([17u8; 20]), H160::from([41u8; 20]), H160::from([12u8; 20]), H160::from([231u8; 20])]]; 89 | let accepted_arr = vec_vec_addr.hash_encode(); 90 | assert_eq!(expected_arr, accepted_arr); 91 | } 92 | } -------------------------------------------------------------------------------- /enigma-principal/healthcheck.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | OK=$(curl -s -o /dev/null -X POST \ 4 | -d '{"jsonrpc": "2.0", "id": "1", "method": "getHealthCheck", "params": []}' \ 5 | -H "Content-Type: application/json" http://localhost:3040 | jq -r '.result') 6 | 7 | if [ "$OK" == "true" ]; then 8 | exit 0 9 | else 10 | exit 1 11 | fi -------------------------------------------------------------------------------- /enigma-principal/test_json_rpc.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #PARAMS="[\"84a46461746181a75265717565737493dc0020cca7cc937b64ccb8cccacca5cc8f03721bccb6ccbacccf5c78cccb235fccebcce0cce70b1bcc84cccdcc99541461cca0cc8edc002016367accacccb67a4a017ccc8dcca8ccabcc95682ccccb390863780f7114ccddcca0cca0cce0ccc55644ccc7ccc4dc0020ccb1cce9cc9324505bccd32dcca0cce1ccf85dcccf5e19cca0cc9dccb0481ecc8a15ccf62c41cceb320304cca8cce927a269649c1363ccb3301c101f33cce1cc9a0524a67072656669789e456e69676d61204d657373616765a67075626b6579dc0040cce5ccbe28cc9dcc9a2eccbd08ccc0457a5f16ccdfcc9fccdc256c5d5f6c3514cccdcc95ccb47c11ccc4cccd3e31ccf0cce4ccefccc83ccc80cce8121c3939ccbb2561cc80ccec48ccbecca8ccc569ccd2cca3ccda6bcce415ccfa20cc9bcc98ccda\", \"43f19586b0a0ae626b9418fe8355888013be1c9b4263a4b3a27953de641991e936ed6c4076a2a383b3b001936bf0eb6e23c78fbec1ee36f19c6a9d24d75e9e081c\"]" 3 | PARAMS="[\"84a67072656669789e456e69676d61204d657373616765a46461746181a75265717565737491dc0020ccfd1454ccbacca9334acc92415f3bcc850919ccaaccc121cc9fccc7cccc7a74ccbd7a25cc8475ccbc677867cc89a67075626b6579dc00404bccfb4accb2ccadccb535cc9cccf0411926ccf92dcc857bcc8555cccd5774ccf1682651ccf5cca0ccab533349cc867314cc8871cc8c0dccf9ccad1734cc89cce1cc9650ccffccabcc8accda352b18ccc0ccf94059ccae6f69ccd9ccf03d2fa269649c000000000000000000000001\",\"10c253d64fa9d079c73cb1e1935afe6a48625b5004e6be6f512bb476391bb33c3084ecbf175470c8cce2cb3fc1dafc5066c82becf8ebab700f26c2a0b48a4bf71c\"]" 4 | curl -X POST --data "{\"jsonrpc\": \"2.0\", \"method\": \"getStateKeys\", \"params\": ${PARAMS}, \"id\": 1}" -H "Content-Type: application/json" http://127.0.0.1:3040/ 5 | 6 | -------------------------------------------------------------------------------- /enigma-runtime-t/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "enigma-runtime-t" 3 | version = "0.3.0" 4 | authors = ["Elichai Turkel "] 5 | 6 | [dependencies] 7 | enigma-types = { path = "../enigma-types", default-features = false, features = ["sgx"] } 8 | enigma-crypto = { path = "../enigma-crypto", default-features = false, features = ["sgx", "asymmetric"] } 9 | enigma-tools-t = { path = "../enigma-tools-t" } 10 | 11 | rmp-serde = { git = "https://github.com/enigmampc/msgpack-rust.git", rev = "0.14.0-sgx-1.0.9" } 12 | json-patch = { git = "https://github.com/enigmampc/json-patch.git", rev = "0.2.5-sgx-1.0.9" } 13 | serde_json = { git = "https://github.com/enigmampc/serde-json-sgx.git", rev = "1.0.39-sgx-1.0.9" } 14 | serde = { git = "https://github.com/mesalock-linux/serde-sgx.git", rev = "sgx_1.0.9", default-features = false, features=["serde_derive"] } 15 | wasmi = { git = "https://github.com/enigmampc/wasmi", rev = "0.4.2-sgx-1.0.9" } 16 | pwasm-utils = { git = "https://github.com/enigmampc/wasm-utils.git", rev = "0.5.0-sgx-1.0.9", default-features = false } 17 | parity-wasm = { git = "https://github.com/enigmampc/parity-wasm.git", branch = "enigma", default-features = false } 18 | 19 | sgx_tstd = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9" } 20 | sgx_types = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9" } 21 | sgx_trts = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9" } -------------------------------------------------------------------------------- /enigma-runtime-t/src/data/delta.rs: -------------------------------------------------------------------------------- 1 | use enigma_tools_t::common::errors_t::EnclaveError; 2 | use enigma_crypto::hash::Keccak256; 3 | use enigma_crypto::{symmetric, Encryption}; 4 | use enigma_types::{Hash256, ContractAddress, StateKey}; 5 | use json_patch; 6 | use rmps::{Deserializer, Serializer}; 7 | use serde::{Deserialize, Serialize}; 8 | use std::vec::Vec; 9 | 10 | #[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] 11 | pub struct StatePatch { 12 | pub patch: json_patch::Patch, 13 | pub previous_hash: Hash256, 14 | #[serde(skip)] 15 | pub contract_address: ContractAddress, 16 | #[serde(skip)] 17 | pub index: u32, 18 | } 19 | 20 | #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Default)] 21 | pub struct EncryptedPatch { 22 | pub data: Vec, 23 | pub contract_address: ContractAddress, 24 | pub index: u32, 25 | } 26 | 27 | impl EncryptedPatch { 28 | pub fn keccak256_patch(&self) -> Hash256 { 29 | self.data.keccak256() 30 | } 31 | } 32 | 33 | impl<'a> Encryption<&'a StateKey, EnclaveError, EncryptedPatch, [u8; 12]> for StatePatch { 34 | fn encrypt_with_nonce(self, key: &StateKey, _iv: Option<[u8; 12]>) -> Result { 35 | let mut buf = Vec::new(); 36 | self.serialize(&mut Serializer::new(&mut buf))?; 37 | let data = symmetric::encrypt_with_nonce(&buf, key, _iv)?; 38 | let contract_address = self.contract_address; 39 | let index = self.index; 40 | Ok(EncryptedPatch { data, contract_address, index }) 41 | } 42 | 43 | fn decrypt(enc: EncryptedPatch, key: &StateKey) -> Result { 44 | let dec = symmetric::decrypt(&enc.data, key)?; 45 | let mut des = Deserializer::new(&dec[..]); 46 | let mut back: Self = Deserialize::deserialize(&mut des)?; 47 | back.contract_address = enc.contract_address; 48 | back.index = enc.index; 49 | Ok(back) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /enigma-runtime-t/src/data/state.rs: -------------------------------------------------------------------------------- 1 | use crate::data::{DeltasInterface, IOInterface, StatePatch}; 2 | use enigma_tools_t::common::errors_t::{EnclaveError, EnclaveError::*, EnclaveSystemError::*}; 3 | use enigma_types::{ContractAddress, StateKey}; 4 | use enigma_crypto::{symmetric, Encryption}; 5 | use enigma_types::Hash256; 6 | use json_patch; 7 | use rmps::{Deserializer, Serializer}; 8 | use serde::{Deserialize, Serialize}; 9 | use serde_json::{from_value, Error, Value}; 10 | use std::string::ToString; 11 | use std::vec::Vec; 12 | use data::EncryptedPatch; 13 | 14 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Default)] 15 | pub struct ContractState { 16 | #[serde(skip)] 17 | pub contract_address: ContractAddress, 18 | pub json: Value, 19 | pub delta_hash: Hash256, 20 | pub delta_index: u32, 21 | } 22 | 23 | #[derive(Debug, PartialEq, Clone)] 24 | pub struct EncryptedContractState { 25 | pub contract_address: ContractAddress, 26 | pub json: Vec, 27 | } 28 | 29 | impl ContractState { 30 | pub fn new(contract_address: ContractAddress) -> ContractState { 31 | let json = serde_json::from_str("{}").unwrap(); 32 | ContractState { contract_address, json,.. Default::default() } 33 | } 34 | 35 | pub fn is_initial(&self) -> bool{ 36 | self.delta_index == 0 && self.delta_hash.is_zero() 37 | } 38 | } 39 | 40 | impl IOInterface for ContractState { 41 | fn read_key(&self, key: &str) -> Result 42 | where for<'de> T: Deserialize<'de> { 43 | from_value(self.json[key].clone()) 44 | } 45 | 46 | fn write_key(&mut self, key: &str, value: &Value) -> Result<(), EnclaveError> { 47 | self.json[key] = value.clone(); 48 | Ok(()) 49 | } 50 | 51 | fn remove_key(&mut self, key: &str) { 52 | if let Some(ref mut v) = self.json.as_object_mut() { 53 | v.remove(key); 54 | } 55 | } 56 | } 57 | 58 | impl<'a> DeltasInterface for ContractState { 59 | fn apply_delta(&mut self, delta: EncryptedPatch, key: &'a StateKey) -> Result<(), EnclaveError> { 60 | let delta_hash = delta.keccak256_patch(); 61 | let dec_delta = StatePatch::decrypt(delta.clone(), key)?; 62 | if dec_delta.previous_hash != self.delta_hash { 63 | return Err(SystemError(StateError { err: "Hashes don't match, Failed Applying the delta".to_string() })); 64 | } 65 | json_patch::patch(&mut self.json, &dec_delta.patch)?; 66 | self.delta_hash = delta_hash; 67 | self.delta_index = dec_delta.index; 68 | Ok(()) 69 | } 70 | 71 | fn generate_delta_and_update_state(old: &Self, new: &mut Self, key: &'a StateKey) -> Result { 72 | if old.delta_hash.is_zero() { 73 | new.delta_index = 0; 74 | } else { 75 | new.delta_index = &old.delta_index+1; 76 | } 77 | let delta = StatePatch{ 78 | patch: json_patch::diff(&old.json, &new.json), 79 | previous_hash: old.delta_hash, 80 | contract_address: old.contract_address, 81 | index: new.delta_index, 82 | }; 83 | let enc_delta = delta.encrypt(key)?; 84 | new.delta_hash = enc_delta.keccak256_patch(); 85 | Ok(enc_delta) 86 | } 87 | } 88 | 89 | impl<'a> Encryption<&'a StateKey, EnclaveError, EncryptedContractState, [u8; 12]> for ContractState { 90 | fn encrypt_with_nonce(self, key: &StateKey, _iv: Option<[u8; 12]>) -> Result, EnclaveError> { 91 | let mut buf = Vec::new(); 92 | self.serialize(&mut Serializer::new(&mut buf))?; 93 | let enc = symmetric::encrypt_with_nonce(&buf, key, _iv)?; 94 | Ok(EncryptedContractState { contract_address: self.contract_address, json: enc }) 95 | } 96 | 97 | fn decrypt(enc: EncryptedContractState, key: &StateKey) -> Result { 98 | let dec = symmetric::decrypt(&enc.json, key)?; 99 | let mut des = Deserializer::new(&dec[..]); 100 | let mut state: ContractState = Deserialize::deserialize(&mut des)?; 101 | state.contract_address = enc.contract_address; 102 | Ok(state) 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /enigma-runtime-t/src/gas.rs: -------------------------------------------------------------------------------- 1 | 2 | pub use pwasm_utils::{inject_gas_counter, rules}; 3 | 4 | /// Wasm cost table 5 | pub struct WasmCosts { 6 | /// Default opcode cost 7 | pub regular: u32, 8 | /// Div operations multiplier. 9 | pub div: u32, 10 | /// Div operations multiplier. 11 | pub mul: u32, 12 | /// Memory (load/store) operations multiplier. 13 | pub mem: u32, 14 | /// General static query of U256 value from env-info 15 | pub static_u256: u32, 16 | /// General static query of Address value from env-info 17 | pub static_address: u32, 18 | /// Memory stipend. Amount of free memory (in 64kb pages) each contract can use for stack. 19 | pub initial_mem: u32, 20 | /// Grow memory cost, per page (64kb) 21 | pub grow_mem: u32, 22 | /// Memory copy cost, per byte 23 | pub memcpy: u32, 24 | /// Max stack height (native WebAssembly stack limiter) 25 | pub max_stack_height: u32, 26 | /// Cost of wasm opcode is calculated as TABLE_ENTRY_COST * `opcodes_mul` / `opcodes_div` 27 | pub opcodes_mul: u32, 28 | /// Cost of wasm opcode is calculated as TABLE_ENTRY_COST * `opcodes_mul` / `opcodes_div` 29 | pub opcodes_div: u32, 30 | } 31 | 32 | impl Default for WasmCosts { 33 | fn default() -> Self { 34 | WasmCosts { 35 | regular: 1, 36 | div: 16, 37 | mul: 4, 38 | mem: 2, 39 | static_u256: 64, 40 | static_address: 40, 41 | initial_mem: 4096, 42 | grow_mem: 8192, 43 | memcpy: 1, 44 | max_stack_height: 64 * 1024, 45 | opcodes_mul: 3, 46 | opcodes_div: 8, 47 | } 48 | } 49 | } 50 | 51 | pub fn gas_rules(wasm_costs: &WasmCosts) -> rules::Set { 52 | rules::Set::new(wasm_costs.regular, { 53 | let mut vals = ::std::collections::BTreeMap::new(); 54 | vals.insert(rules::InstructionType::Load, rules::Metering::Fixed(wasm_costs.mem as u32)); 55 | vals.insert(rules::InstructionType::Store, rules::Metering::Fixed(wasm_costs.mem as u32)); 56 | vals.insert(rules::InstructionType::Div, rules::Metering::Fixed(wasm_costs.div as u32)); 57 | vals.insert(rules::InstructionType::Mul, rules::Metering::Fixed(wasm_costs.mul as u32)); 58 | vals 59 | }) 60 | .with_grow_cost(wasm_costs.grow_mem) 61 | //.with_forbidden_floats() 62 | } 63 | 64 | #[derive(Debug, Clone)] 65 | pub struct RuntimeWasmCosts { 66 | pub write_value: u64, 67 | pub write_additional_byte: u64, 68 | pub deploy_byte: u64, 69 | pub execution: u64, 70 | } 71 | 72 | impl Default for RuntimeWasmCosts { 73 | fn default() -> Self { 74 | RuntimeWasmCosts { 75 | write_value: 10, 76 | write_additional_byte: 1, 77 | deploy_byte: 1, 78 | execution: 10_000, 79 | } 80 | } 81 | } 82 | 83 | #[derive(Debug, Clone)] 84 | pub struct RuntimeGas { 85 | pub counter: u64, 86 | pub limit: u64, 87 | pub refund: u64, 88 | pub costs: RuntimeWasmCosts, 89 | } -------------------------------------------------------------------------------- /enigma-tools-m/Cargo.toml: -------------------------------------------------------------------------------- 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-tools-m" 6 | version = "0.3.0" 7 | authors = ["Elichai Turkel "] 8 | edition = "2018" 9 | 10 | [dependencies] 11 | enigma-types = { path = "../enigma-types" } 12 | enigma-crypto = { path = "../enigma-crypto", default-features = false, features = ["hash"] } 13 | 14 | log-derive = "0.3" 15 | log = { version = "0.4.6", default-features = false } 16 | failure = { version = "0.1", default-features = false, features = ["derive"] } 17 | etcommon-bigint = { version = "0.2", default-features = false, features = ["rlp"] } 18 | etcommon-rlp = {version = "0.2", default-features = false} 19 | rustc-hex = { version = "2.0.1", default-features = false } 20 | 21 | ethabi_std = { package = "ethabi", version = "8.0.1", optional = true } 22 | ethereum_types_std = { package = "ethereum-types", version = "0.6", optional = true } 23 | rmp_serde_std = { package = "rmp-serde", version = "0.14.0", optional = true } 24 | serde_std = { package = "serde", version = "1.0", default-features = false, features = ["derive"], optional = true } 25 | serde_json_std = { package = "serde_json", version = "1.0", optional = true } 26 | 27 | 28 | ethabi_sgx = { package = "ethabi", git = "https://github.com/enigmampc/ethabi.git", rev = "8.0.1-sgx-1.0.9", optional = true } 29 | # we don't use sgx on ethereum-types 30 | ethereum_types_sgx = { package = "ethereum-types", git = "https://github.com/enigmampc/parity-common.git", rev = "0.7.0-sgx-1.0.9", default-features = false, optional = true } 31 | rmp_serde_sgx = { package = "rmp-serde", git = "https://github.com/enigmampc/msgpack-rust.git", rev = "0.14.0-sgx-1.0.9", optional = true } 32 | sgx_tstd = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9", optional = true } 33 | serde_sgx = { package = "serde", git = "https://github.com/mesalock-linux/serde-sgx.git", rev = "sgx_1.0.9", default-features = false, features = ["derive"], optional = true } 34 | serde_json_sgx = { package = "serde_json", git = "https://github.com/enigmampc/serde-json-sgx.git", rev = "1.0.39-sgx-1.0.9", optional = true } 35 | 36 | [features] 37 | default = ["std"] 38 | std = ["ethabi_std", "enigma-types/std", "ethereum_types_std", "enigma-crypto/std", "rmp_serde_std", "serde_std", "serde_json_std"] 39 | sgx = ["ethabi_sgx", "sgx_tstd", "enigma-types/sgx", "ethereum_types_sgx", "enigma-crypto/sgx", "rmp_serde_sgx", "serde_sgx", "serde_json_sgx"] 40 | -------------------------------------------------------------------------------- /enigma-tools-m/src/common/errors.rs: -------------------------------------------------------------------------------- 1 | //! # Errors 2 | //! This is a module for the errors of this crate. 3 | //! we use Failure to handle the Error and Display traits and other conversions. 4 | //! 5 | use failure::Fail; 6 | 7 | /// This Error enum is used to represent errors from this library. 8 | /// Pro tip: If you want to add a string message to the error and you always hard code it, 9 | /// then you can use `&'static str` instead of String, this will make your code much nicer. 10 | #[derive(Debug, Fail, Clone)] 11 | pub enum ToolsError { 12 | /// The `MessagingError` error. 13 | /// 14 | /// This error means that there was a Messaging problem (e.g. couldn't deserialize a message) 15 | #[fail(display = "There's an error with the messaging: {}", err)] 16 | MessagingError { 17 | /// `Err` is the custom message that should explain what and where was the problem. 18 | err: &'static str 19 | }, 20 | } 21 | -------------------------------------------------------------------------------- /enigma-tools-m/src/common/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod errors; 2 | pub mod utils; -------------------------------------------------------------------------------- /enigma-tools-m/src/common/utils.rs: -------------------------------------------------------------------------------- 1 | //! # Mutual Utils. 2 | //! This module contain some handy utils. 3 | //! Right now only a trait that can convert `[u8; 64]` to a 20 bytes Ethereum address 4 | //! or a 20 bytes Ethereum address String in hex representation. 5 | 6 | use crate::localstd::string::String; 7 | use enigma_crypto::hash::Keccak256; 8 | use rustc_hex::ToHex; 9 | 10 | #[cfg(feature = "sgx")] 11 | use crate::localstd::sync::{SgxMutex as Mutex, SgxMutexGuard as MutexGuard}; 12 | 13 | #[cfg(feature = "std")] 14 | use crate::localstd::sync::{Mutex, MutexGuard}; 15 | 16 | /// A trait that is basically a shortcut for `mutex.lock().expect(format!("{} mutex is posion", name))` 17 | /// you instead call `mutex.lock_expect(name)` and it will act the same. 18 | pub trait LockExpectMutex { 19 | /// See trait documentation. a shortcut for `lock()` and `expect()` 20 | fn lock_expect(&self, name: &str) -> MutexGuard; 21 | } 22 | 23 | impl LockExpectMutex for Mutex { 24 | fn lock_expect(&self, name: &str) -> MutexGuard { self.lock().unwrap_or_else(|_| panic!("{} mutex is poison", name)) } 25 | } 26 | 27 | /// A trait to convert an object into an Ethereum Address 28 | pub trait EthereumAddress { 29 | /// This should convert the object(by hashing and slicing) into a String type 40 characters Ethereum address. 30 | fn address_string(&self) -> T 31 | where T: Sized; 32 | /// This should convert the object(by hashing and slicing) into a 20 byte Ethereum address. 33 | fn address(&self) -> P 34 | where P: Sized; 35 | } 36 | 37 | impl EthereumAddress for [u8; 64] { 38 | // TODO: Maybe add a checksum address 39 | fn address_string(&self) -> String { 40 | let mut result: String = String::from("0x"); 41 | let hex: String = self.keccak256()[12..32].to_hex(); 42 | result.push_str(&hex); 43 | result 44 | } 45 | 46 | fn address(&self) -> [u8; 20] { 47 | let mut result = [0u8; 20]; 48 | result.copy_from_slice(&self.keccak256()[12..32]); 49 | result 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /enigma-tools-m/src/keeper_types.rs: -------------------------------------------------------------------------------- 1 | #![allow(missing_docs)] // This should be removed after @fredfortier will document this module. 2 | 3 | use crate::localstd::{vec, vec::Vec}; 4 | use log::debug; 5 | use log_derive::logfn; 6 | 7 | use bigint; 8 | use crate::ethabi::{encode, Address, Bytes, Token}; 9 | use crate::ethereum_types::{H160, U256}; 10 | use enigma_crypto::hash::Keccak256; 11 | use enigma_types::ContractAddress; 12 | pub use rlp::{decode, encode as rlpEncode, Encodable, Decodable, DecoderError, UntrustedRlp, RlpStream}; 13 | 14 | pub const EPOCH_CAP: usize = 2; 15 | 16 | pub trait FromBigint: Sized { 17 | fn from_bigint(_: T) -> Self; 18 | } 19 | 20 | impl FromBigint for H160 { 21 | fn from_bigint(b: bigint::H160) -> Self { H160(b.0) } 22 | } 23 | 24 | impl FromBigint for U256 { 25 | fn from_bigint(b: bigint::U256) -> Self { U256(b.0) } 26 | } 27 | 28 | pub trait RawEncodable { 29 | fn raw_encode(&self) -> Bytes; 30 | } 31 | 32 | #[derive(Clone)] 33 | struct WorkerSelectionToken { 34 | pub seed: U256, 35 | pub sc_addr: ContractAddress, 36 | pub nonce: U256, 37 | } 38 | 39 | impl RawEncodable for WorkerSelectionToken { 40 | /// Encode the WorkerSelectionToken as Ethereum ABI parameters 41 | fn raw_encode(&self) -> Bytes { 42 | let tokens = vec![Token::Uint(self.seed), Token::FixedBytes(self.sc_addr.to_vec()), Token::Uint(self.nonce)]; 43 | encode(&tokens) 44 | } 45 | } 46 | 47 | #[derive(Debug, Clone)] 48 | pub struct InputWorkerParams { 49 | pub km_block_number: U256, 50 | pub workers: Vec
, 51 | pub stakes: Vec, 52 | } 53 | 54 | impl InputWorkerParams { 55 | /// Run the worker selection algorithm against the current epoch 56 | /// 57 | /// # Arguments 58 | /// 59 | /// * `sc_addr` - The Secret Contract address 60 | /// * `seed` - The random seed for the selected epoch 61 | /// 62 | #[logfn(DEBUG)] 63 | pub fn get_selected_worker(&self, sc_addr: ContractAddress, seed: U256) -> Option
{ 64 | debug!("Finding selected worker for sc_addr: {:?} and seed: {:?}", sc_addr, seed); 65 | let workers = self.get_selected_workers(sc_addr, seed, None); 66 | if workers.is_empty() { 67 | None 68 | } else { 69 | Some(workers[0]) 70 | } 71 | } 72 | 73 | #[logfn(DEBUG)] 74 | fn get_selected_workers(&self, sc_addr: ContractAddress, seed: U256, group_size: Option) -> Vec
{ 75 | let mut selected_workers = Vec::new(); 76 | if self.workers.is_empty() || self.workers.len() != self.stakes.len() { 77 | debug!("Invalid worker selection parameters {:?}", self); 78 | return selected_workers; 79 | } 80 | let mut balance_sum = U256::zero(); 81 | for &balance in &self.stakes { 82 | balance_sum += balance; 83 | } 84 | // Using the same type as the Enigma contract 85 | let mut nonce = U256::zero(); 86 | let group_size = group_size.unwrap_or(1); 87 | 88 | while selected_workers.len() < group_size as usize { 89 | let token = WorkerSelectionToken { seed, sc_addr, nonce }; 90 | // This is equivalent to encodePacked in Solidity 91 | let hash = token.raw_encode().keccak256(); 92 | let mut rand_val: U256 = U256::from(*hash) % balance_sum; 93 | debug!("The initial random value: {:?}", rand_val.0); 94 | let mut selected_worker = self.workers.last().unwrap(); 95 | 96 | for (i, worker) in self.workers.iter().enumerate() { 97 | let (new_rand, overflow) = rand_val.overflowing_sub(self.stakes[i]); 98 | if overflow || new_rand.is_zero() { 99 | selected_worker = worker; 100 | break; 101 | } 102 | rand_val = new_rand; 103 | debug!("The next random value: {:?}", rand_val.0); 104 | } 105 | if !selected_workers.contains(selected_worker) { 106 | selected_workers.push(*selected_worker); 107 | } 108 | nonce += 1.into(); 109 | } 110 | debug!("The selected workers: {:?}", selected_workers); 111 | selected_workers 112 | } 113 | } 114 | 115 | impl Decodable for InputWorkerParams { 116 | fn decode(rlp: &UntrustedRlp) -> Result { 117 | Ok(Self { 118 | km_block_number: U256::from_bigint(rlp.val_at(0)?), 119 | workers: rlp.list_at(1)?.iter().map(|a| H160::from_bigint(*a)).collect::>(), 120 | stakes: rlp.list_at(2)?.iter().map(|b| U256::from_bigint(*b)).collect::>(), 121 | }) 122 | } 123 | } 124 | 125 | impl Encodable for InputWorkerParams { 126 | fn rlp_append(&self, s: &mut RlpStream) { 127 | s.begin_list(3); 128 | s.append(&bigint::U256(self.km_block_number.0)); 129 | s.append_list(&self.workers.iter().map(|a| bigint::H160(a.0)).collect::>()); 130 | s.append_list(&self.stakes.iter().map(|b| bigint::U256(b.0)).collect::>()); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /enigma-tools-m/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(all(not(feature = "std"), not(test)), no_std)] 2 | #![deny(unused_extern_crates, missing_docs)] 3 | //! # Enigma Tools Mutual 4 | //! This library provides tools for both untrusted and trusted sides of the SGX.
5 | //! It should supersede both `enigma-tools-t` and `enigma-tools-u`. 7 | //! This crate is Rust 2018 Edition, 8 | //! meaning there's no `extern crate` and `use` statements need to start with `crate`/`self`/`super`. 9 | 10 | mod common; 11 | pub mod keeper_types; 12 | pub mod primitives; 13 | pub use crate::common::errors::ToolsError; 14 | pub use crate::common::utils; 15 | 16 | #[cfg(feature = "std")] 17 | use {ethabi_std as ethabi, ethereum_types_std as ethereum_types, rmp_serde_std as rmp_serde, serde_json_std as serde_json, 18 | serde_std as serde, std as localstd}; 19 | 20 | #[cfg(feature = "sgx")] 21 | use {ethabi_sgx as ethabi, ethereum_types_sgx as ethereum_types, rmp_serde_sgx as rmp_serde, serde_json_sgx as serde_json, 22 | serde_sgx as serde, sgx_tstd as localstd}; 23 | -------------------------------------------------------------------------------- /enigma-tools-m/src/primitives/mod.rs: -------------------------------------------------------------------------------- 1 | //! # Primitives. 2 | //! This is a sub module for more modules. 3 | pub mod km_primitives; -------------------------------------------------------------------------------- /enigma-tools-t/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "enigma-tools-t" 3 | version = "0.3.0" 4 | authors = ["Elichai-Turkel "] 5 | description = "Tools used by the trusted part of the Enigma core and Principal node." 6 | 7 | [dependencies] 8 | enigma-types = { path = "../enigma-types", default-features = false, features = ["sgx"] } 9 | enigma-tools-m = { path = "../enigma-tools-m", default-features = false, features = ["sgx"] } 10 | enigma-crypto = { path = "../enigma-crypto", default-features = false, features = ["sgx", "asymmetric"] } 11 | 12 | failure = { version = "0.1", default-features = false, features = ["derive"] } 13 | etcommon-rlp = {version = "0.2", default-features = false} 14 | etcommon-hexutil = { version = "0.2", default-features = false } 15 | etcommon-bigint = { version = "0.2", default-features = false, features = ["rlp"] } 16 | rustc-hex = { version = "2.0", default-features = false } 17 | 18 | parity-wasm = { git = "https://github.com/enigmampc/parity-wasm.git", branch = "enigma", default-features = false } 19 | pwasm-utils = { git = "https://github.com/enigmampc/wasm-utils.git", rev = "0.5.0-sgx-1.0.9", default-features = false } 20 | 21 | rmp-serde = { git = "https://github.com/enigmampc/msgpack-rust.git", rev = "0.14.0-sgx-1.0.9" } 22 | serde = { git = "https://github.com/mesalock-linux/serde-sgx.git", rev = "sgx_1.0.9", default-features = false, features=["serde_derive"] } 23 | json-patch = { git = "https://github.com/enigmampc/json-patch.git", rev = "0.2.5-sgx-1.0.9", default-features = false } 24 | wasmi = { git = "https://github.com/enigmampc/wasmi", rev = "0.4.2-sgx-1.0.9" } 25 | serde_json = { git = "https://github.com/enigmampc/serde-json-sgx.git", rev = "1.0.39-sgx-1.0.9" } 26 | 27 | sgx_types = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9" } 28 | sgx_tstd = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9" } 29 | sgx_trts = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9" } 30 | sgx_tse = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9" } 31 | sgx_tseal = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9" } 32 | -------------------------------------------------------------------------------- /enigma-tools-t/src/build_arguments_g/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod rlp; 2 | use self::rlp::decode_args; 3 | use enigma_crypto::{asymmetric::KeyPair, symmetric::decrypt}; 4 | use enigma_types::DhKey; 5 | use crate::common::errors_t::{EnclaveError, EnclaveError::*, FailedTaskError::*}; 6 | use rustc_hex::FromHex; 7 | use std::string::String; 8 | use std::string::ToString; 9 | use std::vec::Vec; 10 | 11 | pub fn get_key() -> [u8; 32] { 12 | let _my_priv_key: Vec = "2987699a6d3a5ebd07f4caf422fad2809dcce942cd9db266ed8e2be02cf95ee9".from_hex().unwrap(); 13 | let mut my_priv_key = [0u8; 32]; 14 | my_priv_key.clone_from_slice(&_my_priv_key); 15 | let my_keys = KeyPair::from_slice(&my_priv_key).unwrap(); 16 | let _client_pub_key: Vec = "5587fbc96b01bfe6482bf9361a08e84810afcc0b1af72a8e4520f98771ea1080681e8a2f9546e5924e18c047fa948591dba098bffaced50f97a41b0050bdab99".from_hex().unwrap(); 17 | let mut client_pub_key = [0u8; 64]; 18 | client_pub_key.clone_from_slice(&_client_pub_key); 19 | my_keys.derive_key(&client_pub_key).unwrap() 20 | } 21 | 22 | pub fn get_types(function: &str) -> Result<(String, String), EnclaveError> { 23 | let start_arg_index; 24 | let end_arg_index; 25 | 26 | match function.find('(') { 27 | Some(x) => start_arg_index = x, 28 | None => return Err(FailedTaskError(InputError { message: "'callable' signature is illegal".to_string() })), 29 | } 30 | 31 | match function.find(')') { 32 | Some(x) => end_arg_index = x, 33 | None => return Err(FailedTaskError(InputError { message: "'callable' signature is illegal".to_string() })), 34 | } 35 | 36 | Ok((function[start_arg_index + 1..end_arg_index].to_string(), String::from(&function[..start_arg_index]))) 37 | } 38 | 39 | pub fn get_args(callable_args: &[u8], types: &[String], key: &[u8; 32]) -> Result, EnclaveError> { 40 | decode_args(callable_args, types, key) 41 | } 42 | 43 | // decrypt the arguments which all are sent encrypted and return the solidity abi serialized data 44 | pub fn decrypt_args(callable_args: &[u8], key: &DhKey) -> Result, EnclaveError>{ 45 | // if args is empty we don't want to try decrypting the slice- it will lead to an error 46 | if callable_args.is_empty() { 47 | Ok(callable_args.to_vec()) 48 | } 49 | else { 50 | Ok(decrypt(callable_args, key)?) 51 | } 52 | } 53 | 54 | pub fn decrypt_callable(callable: &[u8], key: &DhKey) -> Result, EnclaveError> { 55 | if callable.is_empty(){ 56 | Err(FailedTaskError(InputError { message: "called function representation is empty".to_string()})) 57 | } else { 58 | Ok(decrypt(callable, key)?) 59 | } 60 | } 61 | 62 | pub fn extract_types(types: &str) -> Vec{ 63 | let mut types_vector: Vec = vec![]; 64 | let types_iterator = types.split(','); 65 | for each_type in types_iterator { 66 | types_vector.push(each_type.to_string()); 67 | } 68 | types_vector 69 | } 70 | -------------------------------------------------------------------------------- /enigma-tools-t/src/common/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod errors_t; -------------------------------------------------------------------------------- /enigma-tools-t/src/esgx/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod ocalls_t; -------------------------------------------------------------------------------- /enigma-tools-t/src/esgx/ocalls_t.rs: -------------------------------------------------------------------------------- 1 | use crate::common::errors_t::EnclaveError; 2 | use enigma_types::traits::SliceCPtr; 3 | use sgx_types::sgx_status_t; 4 | use std::{path::PathBuf, str}; 5 | 6 | const PATH_MAX: usize = 4096; // linux/limits.h - this depends on the FS. 7 | 8 | extern "C" { 9 | fn ocall_get_home(output: *mut u8, result_len: &mut usize) -> sgx_status_t; 10 | fn ocall_save_to_memory(ptr: *mut u64, data_ptr: *const u8, data_len: usize) -> sgx_status_t; 11 | } 12 | 13 | pub fn get_home_path() -> Result { 14 | // Get Home path via Ocall 15 | let mut home_slice: [u8; PATH_MAX] = [0; PATH_MAX]; 16 | let mut result_len: usize = 0; 17 | unsafe { ocall_get_home(home_slice.as_mut_ptr(), &mut result_len); } 18 | let home_str = str::from_utf8(&home_slice[..result_len])?; 19 | debug_println!("Back from Ocall: {}", &home_str); 20 | 21 | Ok(PathBuf::from(home_str)) 22 | } 23 | 24 | 25 | // TODO: Replace u64 with *const u8, and pass it via the ocall using *const *const u8 26 | pub fn save_to_untrusted_memory(data: &[u8]) -> Result { 27 | let mut ptr = 0u64; 28 | match unsafe { ocall_save_to_memory(&mut ptr as *mut u64, data.as_c_ptr(), data.len()) } { 29 | sgx_status_t::SGX_SUCCESS => Ok(ptr), 30 | e => Err(e.into()), 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /enigma-tools-t/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![crate_type = "lib"] 3 | #![warn(unused_extern_crates)] 4 | 5 | extern crate enigma_types; 6 | extern crate enigma_crypto; 7 | extern crate enigma_tools_m; 8 | 9 | #[macro_use] 10 | extern crate sgx_tstd as std; 11 | #[macro_use] 12 | extern crate failure; 13 | extern crate json_patch; 14 | extern crate parity_wasm; 15 | extern crate pwasm_utils; 16 | extern crate sgx_tse; 17 | extern crate sgx_tseal; 18 | extern crate sgx_types; 19 | 20 | extern crate bigint; 21 | extern crate hexutil; 22 | extern crate rlp; 23 | extern crate wasmi; 24 | extern crate rustc_hex; 25 | 26 | #[macro_use] 27 | pub mod macros; 28 | 29 | pub mod build_arguments_g; 30 | pub mod common; 31 | pub mod quote_t; 32 | pub mod document_storage_t; //TODO: Copy of storage_t with more generic naming convention 33 | pub mod storage_t; 34 | pub mod esgx; 35 | 36 | 37 | #[cfg(test)] 38 | mod tests { 39 | #[test] 40 | fn it_works() { 41 | assert_eq!(2 + 2, 4); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /enigma-tools-t/src/macros.rs: -------------------------------------------------------------------------------- 1 | #[macro_export] 2 | macro_rules! debug_println { 3 | ($($arg:tt)*) => { 4 | if cfg!(debug_assertions) { 5 | println!($($arg)*); 6 | } 7 | }; 8 | } -------------------------------------------------------------------------------- /enigma-tools-t/src/quote_t.rs: -------------------------------------------------------------------------------- 1 | use sgx_tse::*; 2 | use sgx_types::*; 3 | 4 | // extra_data size (limit to 64) 5 | static REPORT_DATA_SIZE: usize = 64; 6 | 7 | pub fn create_report_with_data(target_info: &sgx_target_info_t, out_report: &mut sgx_report_t, extra_data: &[u8]) -> sgx_status_t { 8 | let mut report_data = sgx_report_data_t::default(); 9 | // secret data to be attached with the report. 10 | if extra_data.len() > REPORT_DATA_SIZE { 11 | return sgx_status_t::SGX_ERROR_INVALID_PARAMETER; 12 | } 13 | 14 | report_data.d[..extra_data.len()].copy_from_slice(extra_data); 15 | 16 | match rsgx_create_report(&target_info, &report_data) { 17 | Ok(r) => { 18 | *out_report = r; 19 | sgx_status_t::SGX_SUCCESS 20 | } 21 | Err(r) => { 22 | debug_println!("[-] Enclave: error creating report"); 23 | r 24 | } 25 | }; 26 | sgx_status_t::SGX_SUCCESS 27 | } 28 | -------------------------------------------------------------------------------- /enigma-tools-u/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "enigma-tools-u" 3 | version = "0.3.0" 4 | authors = ["Isan-Rivkin "] 5 | description = "Tools used by the untrusted part of the Enigma core and Principal node." 6 | build = "build.rs" 7 | 8 | 9 | [dependencies] 10 | enigma-crypto = { path = "../enigma-crypto" } 11 | enigma-types = { path = "../enigma-types", features = ["std"] } 12 | 13 | serde_json = "1.0" 14 | serde = { version = "1.0", default-features = false, features=["serde_derive"] } 15 | failure = "0.1.3" 16 | reqwest = "0.9.5" 17 | etcommon-bigint = "0.2" 18 | base64 = "0.10.0" 19 | openssl = "0.10" 20 | openssl-sys = "0.9" 21 | rustc-hex = "1.0.0" # 2.0.1? 22 | log = "0.4" 23 | log4rs = {version = "0.9.0", features = ["rolling_file_appender"] } 24 | log-derive = "0.3" 25 | dirs = "1.0.4" 26 | tiny-keccak = { version = "1.5.0", features = ["keccak"] } 27 | # TODO: Change after a new version is released. 28 | # Add more transport layers via features if needed. 29 | web3 = { version = "0.8", default-features = false, features=["http", "tls"] } 30 | ethabi = "8" 31 | ethereum-types = "0.6.0" 32 | rlp = "0.4.3" 33 | 34 | gethostname = "0.2.0" 35 | 36 | sgx_types = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9" } 37 | sgx_urts = { git = "https://github.com/baidu/rust-sgx-sdk.git", rev = "v1.0.9" } 38 | -------------------------------------------------------------------------------- /enigma-tools-u/build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | fn main() { 4 | let sdk_dir = env::var("SGX_SDK").unwrap_or_else(|_| "/opt/intel/sgxsdk".to_string()); 5 | let is_sim = env::var("SGX_MODE").unwrap_or_else(|_| "HW".to_string()); 6 | 7 | println!("cargo:rustc-link-search=native={}/lib64", sdk_dir); 8 | match is_sim.as_ref() { 9 | "SW" => { 10 | println!("cargo:rustc-link-lib=dylib=sgx_urts_sim"); 11 | println!("cargo:rustc-link-lib=dylib=sgx_uae_service_sim"); 12 | } 13 | _ => { 14 | // Treat both HW and undefined as HW 15 | println!("cargo:rustc-link-lib=dylib=sgx_urts"); 16 | println!("cargo:rustc-link-lib=dylib=sgx_uae_service"); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /enigma-tools-u/src/attestation_service/constants.rs: -------------------------------------------------------------------------------- 1 | // the attestation service end-point 2 | pub const ATTESTATION_SERVICE_URL: &str = "https://sgx.enigma.co/api"; 3 | -------------------------------------------------------------------------------- /enigma-tools-u/src/attestation_service/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod constants; 2 | pub mod service; 3 | -------------------------------------------------------------------------------- /enigma-tools-u/src/common_u/errors.rs: -------------------------------------------------------------------------------- 1 | use sgx_types::sgx_status_t; 2 | 3 | // error while request attestation service 4 | #[derive(Fail, Debug)] 5 | #[fail(display = "Error while using the attestation service info = ({})", message)] 6 | pub struct AttestationServiceErr { 7 | pub message: String, 8 | } 9 | 10 | #[derive(Fail, Debug)] 11 | #[fail(display = "Error while decoding the quote = ({})", message)] 12 | pub struct QuoteErr { 13 | pub message: String, 14 | } 15 | 16 | #[derive(Fail, Debug)] 17 | #[fail(display = "Error while decoding the quote = ({})", message)] 18 | pub struct WasmError { 19 | pub message: String, 20 | } 21 | 22 | #[derive(Fail, Debug)] 23 | #[fail(display = "Error while using the web3 server = ({})", message)] 24 | pub struct Web3Error { 25 | pub message: String, 26 | } 27 | 28 | #[derive(Fail, Debug)] 29 | #[fail(display = "SGX Ecall Failed function: {}, status: {}", function, status)] 30 | pub struct SgxError { 31 | pub status: sgx_status_t, 32 | pub function: &'static str, 33 | } 34 | -------------------------------------------------------------------------------- /enigma-tools-u/src/common_u/logging.rs: -------------------------------------------------------------------------------- 1 | //! # Enigma Core Logging. 2 | //! 3 | //! For logs we use the official `log` facade (https://github.com/rust-lang-nursery/log)
4 | //! This module returns loggers according to the inputs (a file logger and a stdout logger)
5 | //! they catch the logs themselves from the `log` facade.
6 | //! Default verbosity for stdout logger is `Error` and each verbose level will increase it accordingly.
7 | //! Default verbosity for the file logger is `Warn` and it's always one level above the stdout logger.
8 | 9 | 10 | use std::{fs::{self}, path::Path}; 11 | use failure::Error; 12 | 13 | use log::{LevelFilter}; 14 | use log4rs::append::console::{ConsoleAppender, Target}; 15 | use log4rs::append::{file::FileAppender, rolling_file::RollingFileAppender}; 16 | use log4rs::config::{Appender, Config, Root, Logger}; 17 | use log4rs::encode::pattern::PatternEncoder; 18 | use log4rs::filter::threshold::ThresholdFilter; 19 | use log4rs::Handle; 20 | use log4rs::append::rolling_file::policy::compound::{trigger::size::SizeTrigger, roll::fixed_window::FixedWindowRoller, CompoundPolicy}; 21 | 22 | const MEGABYTE: u64 = 1048576; 23 | const ARCHIVED_LOGS_NUM: u32 = 3; 24 | const WINDOW_START: u32 = 1; 25 | 26 | pub fn init_logger>(level: log::LevelFilter, data_dir: P, name: String) -> Result { 27 | 28 | // Make sure the directory exists. 29 | fs::create_dir_all(&data_dir)?; 30 | let mut file_path = data_dir.as_ref().to_path_buf(); 31 | 32 | let mut foo = "[{d(%Y-%m-%d %H:%M:%S)}] [".to_string(); 33 | foo.push_str(&name); 34 | foo.push_str("] {h({l:5.15})} {M} -- {m}{n}"); 35 | // Build a stderr logger. 36 | let stdout = ConsoleAppender::builder() 37 | .encoder(Box::new(PatternEncoder::new(&foo))) 38 | .target(Target::Stdout).build(); 39 | 40 | // define how many archived logs there will be aside from the log that will be written into. 41 | // see docs here: 42 | // https://docs.rs/log4rs/0.9.0/log4rs/append/rolling_file/policy/compound/roll/fixed_window/struct.FixedWindowRoller.html 43 | // to understand how it works. 44 | // see this issue as well: 45 | // https://github.com/estk/log4rs/issues/120 46 | let window_size = ARCHIVED_LOGS_NUM; 47 | let pattern = file_path.clone().into_os_string().into_string().unwrap() + "/debug.{}.log"; 48 | let fixed_window_roller = 49 | FixedWindowRoller::builder().base(WINDOW_START).build(&pattern ,window_size).unwrap(); 50 | 51 | let size_limit = 300 * MEGABYTE; // 300MB as max log file size to roll 52 | let size_trigger = SizeTrigger::new(size_limit); 53 | 54 | let compound_policy = CompoundPolicy::new(Box::new(size_trigger),Box::new(fixed_window_roller)); 55 | 56 | file_path.push("debug.0.log"); 57 | let logfile = RollingFileAppender::builder() 58 | // Pattern: https://docs.rs/log4rs/*/log4rs/encode/pattern/index.html 59 | .encoder(Box::new(PatternEncoder::new("[{d(%Y-%m-%d %H:%M:%S)}] [{t}] {l:5.15} {M} -- {m}{n}"))) 60 | .build(file_path, Box::new(compound_policy)) 61 | .unwrap(); 62 | 63 | // Log Trace level output to file where trace is the default level 64 | // and the programmatically specified level to stderr. 65 | // `logger` is used to define a log level for a crate used by the project. 66 | // we want to avoid unnecessary logs so defining the following with a high level. 67 | let config = Config::builder() 68 | .appender(Appender::builder().build("logfile", Box::new(logfile))) 69 | .appender(Appender::builder() 70 | .filter(Box::new(ThresholdFilter::new(level))) 71 | .build("stderr", Box::new(stdout))) 72 | .logger(Logger::builder().build("tokio_zmq", LevelFilter::Warn)) 73 | .logger(Logger::builder().build("hyper", LevelFilter::Warn)) 74 | .logger(Logger::builder().build("tokio_reactor", LevelFilter::Warn)) 75 | .logger(Logger::builder().build("tokio_core", LevelFilter::Warn)) 76 | .logger(Logger::builder().build("web3", LevelFilter::Warn)) 77 | .logger(Logger::builder().build("tokio_threadpool", LevelFilter::Warn)) 78 | .logger(Logger::builder().build("want", LevelFilter::Warn)) 79 | .build(Root::builder().appender("logfile").appender("stderr").build(LevelFilter::Trace)) 80 | .unwrap(); 81 | 82 | // Use this to change log levels at runtime. 83 | // This means you can change the default log level to trace 84 | // if you are trying to debug an issue and need more logs on, then turn it off 85 | // once you are done. 86 | let handle = log4rs::init_config(config).unwrap(); 87 | Ok(handle) 88 | } -------------------------------------------------------------------------------- /enigma-tools-u/src/common_u/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod errors; 2 | pub mod logging; 3 | pub mod os; -------------------------------------------------------------------------------- /enigma-tools-u/src/common_u/os.rs: -------------------------------------------------------------------------------- 1 | use gethostname; 2 | 3 | pub fn hostname() -> String { 4 | gethostname::gethostname().into_string().unwrap() 5 | } -------------------------------------------------------------------------------- /enigma-tools-u/src/esgx/equote.rs: -------------------------------------------------------------------------------- 1 | use base64; 2 | use common_u::errors; 3 | use failure::Error; 4 | use hex::FromHex; 5 | use sgx_types::*; 6 | use std::thread::sleep; 7 | use std::{self, time}; 8 | 9 | extern "C" { 10 | pub fn ecall_get_registration_quote(eid: sgx_enclave_id_t, retval: *mut sgx_status_t, 11 | target_info: *const sgx_target_info_t, report: *mut sgx_report_t) -> sgx_status_t; 12 | 13 | pub fn sgx_init_quote(p_target_info: *mut sgx_target_info_t, p_gid: *mut sgx_epid_group_id_t) -> sgx_status_t; 14 | 15 | pub fn sgx_calc_quote_size(p_sig_rl: *const uint8_t, sig_rl_size: uint32_t, p_quote_size: *mut uint32_t) -> sgx_status_t; 16 | 17 | pub fn sgx_get_quote(p_report: *const sgx_report_t, quote_type: sgx_quote_sign_type_t, 18 | p_spid: *const sgx_spid_t, p_nonce: *const sgx_quote_nonce_t, p_sig_rl: *const uint8_t, 19 | sig_rl_size: uint32_t, p_qe_report: *mut sgx_report_t, p_quote: *mut sgx_quote_t, 20 | quote_size: uint32_t) -> sgx_status_t; 21 | } 22 | 23 | pub fn retry_quote(eid: sgx_enclave_id_t, spid: &str, times: usize) -> Result { 24 | let mut quote = String::new(); 25 | for _ in 0..times { 26 | quote = match produce_quote(eid, spid) { 27 | Ok(q) => q, 28 | Err(e) => { 29 | println!("problem with quote, trying again: {:?}", e); 30 | continue; 31 | } 32 | }; 33 | 34 | if !quote.chars().all(|cur_c| cur_c == 'A') { 35 | return Ok(quote); 36 | } else { 37 | sleep(time::Duration::new(5, 0)); 38 | } 39 | } 40 | Err(errors::QuoteErr { message: quote }.into()) 41 | } 42 | 43 | fn check_busy(func: F) -> (sgx_status_t, T) 44 | where F: Fn() -> (sgx_status_t, T) { 45 | loop { 46 | let (status, rest) = func(); 47 | if status != sgx_status_t::SGX_ERROR_BUSY { 48 | return (status, rest); 49 | } 50 | sleep(time::Duration::new(1, 500_000_000)); 51 | } 52 | } 53 | 54 | #[logfn(TRACE)] 55 | pub fn produce_quote(eid: sgx_enclave_id_t, spid: &str) -> Result { 56 | let spid = spid.from_hex()?; 57 | let mut id = [0; 16]; 58 | id.copy_from_slice(&spid); 59 | let spid: sgx_spid_t = sgx_spid_t { id }; 60 | 61 | // create quote 62 | let (status, (target_info, _gid)) = check_busy(|| { 63 | let mut target_info = sgx_target_info_t::default(); 64 | let mut gid = sgx_epid_group_id_t::default(); 65 | let status = unsafe { sgx_init_quote(&mut target_info, &mut gid) }; 66 | (status, (target_info, gid)) 67 | }); 68 | if status != sgx_status_t::SGX_SUCCESS { 69 | return Err(errors::SgxError { status, function: "sgx_init_quote" }.into()); 70 | } 71 | 72 | // create report 73 | let (status, (report, retval)) = check_busy(move || { 74 | let mut report = sgx_report_t::default(); 75 | let mut retval = sgx_status_t::SGX_SUCCESS; 76 | let status = unsafe { ecall_get_registration_quote(eid, &mut retval, &target_info, &mut report) }; 77 | (status, (report, retval)) 78 | }); 79 | if status != sgx_status_t::SGX_SUCCESS || retval != sgx_status_t::SGX_SUCCESS { 80 | return Err(errors::SgxError { status, function: "ecall_get_registration_quote" }.into()); 81 | } 82 | 83 | 84 | // calc quote size 85 | let (status, quote_size) = check_busy(|| { 86 | let mut quote_size: u32 = 0; 87 | let status = unsafe { sgx_calc_quote_size(std::ptr::null(), 0, &mut quote_size) }; 88 | (status, quote_size) 89 | }); 90 | if status != sgx_status_t::SGX_SUCCESS || quote_size == 0 { 91 | return Err(errors::SgxError { status, function: "sgx_calc_quote_size" }.into()); 92 | } 93 | 94 | // get the actual quote 95 | let (status, the_quote) = check_busy(|| { 96 | let mut the_quote = vec![0u8; quote_size as usize].into_boxed_slice(); 97 | // all of this is according to this: https://software.intel.com/en-us/sgx-sdk-dev-reference-sgx-get-quote 98 | // the `p_qe_report` is null together with the nonce because we don't have an ISV enclave that needs to verify this 99 | // and we don't care about replay attacks because the signing key will stay the same and that's what's important. 100 | let status = unsafe { 101 | sgx_get_quote(&report, 102 | sgx_quote_sign_type_t::SGX_UNLINKABLE_SIGNATURE, 103 | &spid, 104 | std::ptr::null(), 105 | std::ptr::null(), 106 | 0, 107 | std::ptr::null_mut(), 108 | the_quote.as_mut_ptr() as *mut sgx_quote_t, 109 | quote_size, 110 | ) 111 | }; 112 | (status, the_quote) 113 | }); 114 | if status != sgx_status_t::SGX_SUCCESS { 115 | return Err(errors::SgxError { status, function: "sgx_get_quote" }.into()); 116 | } 117 | 118 | let encoded_quote = base64::encode(&the_quote); 119 | Ok(encoded_quote) 120 | } 121 | -------------------------------------------------------------------------------- /enigma-tools-u/src/esgx/general.rs: -------------------------------------------------------------------------------- 1 | use sgx_types::{sgx_attributes_t, sgx_launch_token_t, sgx_misc_attribute_t, SgxResult}; 2 | use sgx_urts::SgxEnclave; 3 | use std::path::{PathBuf, Path}; 4 | use failure::Error; 5 | 6 | pub fn storage_dir>(dir_name: P) -> Result { 7 | let mut path = dirs::home_dir().ok_or_else(|| { 8 | format_err!("Missing home directory") 9 | })?; 10 | trace!("Home dir is {}", path.display()); 11 | path.push(dir_name); 12 | Ok(path) 13 | } 14 | 15 | pub fn init_enclave(enclave_location: &str) 16 | -> SgxResult<(SgxEnclave)> { 17 | let mut launch_token: sgx_launch_token_t = [0; 1024]; 18 | let mut launch_token_updated: i32 = 0; 19 | 20 | // Call sgx_create_enclave to initialize an enclave instance 21 | // Debug Support: set 2nd parameter to 1 22 | let debug = 1; 23 | let mut misc_attr = sgx_misc_attribute_t { secs_attr: sgx_attributes_t { flags: 0, xfrm: 0 }, misc_select: 0 }; 24 | 25 | // `launch_token` and `launch_token_updated` are deprecated according to https://download.01.org/intel-sgx/linux-2.6/docs/Intel_SGX_Developer_Reference_Linux_2.6_Open_Source.pdf 26 | // see https://github.com/apache/incubator-teaclave-sgx-sdk/pull/163 27 | let enclave = SgxEnclave::create(enclave_location, debug, &mut launch_token, &mut launch_token_updated, &mut misc_attr)?; 28 | Ok(enclave) 29 | } 30 | -------------------------------------------------------------------------------- /enigma-tools-u/src/esgx/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod equote; 2 | pub mod general; 3 | pub mod ocalls_u; 4 | 5 | pub use self::general::init_enclave; 6 | -------------------------------------------------------------------------------- /enigma-tools-u/src/esgx/ocalls_u.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_attributes)] 2 | 3 | use std::{ptr, slice}; 4 | use enigma_types::traits::SliceCPtr; 5 | use crate::esgx::general; 6 | 7 | pub static ENCLAVE_DIR: &'static str = ".enigma"; 8 | 9 | #[no_mangle] 10 | pub unsafe extern "C" fn ocall_get_home(output: *mut u8, result_len: &mut usize) { 11 | let path = general::storage_dir(ENCLAVE_DIR).unwrap(); // TODO: Handle the Error here. it wasn't handled before. 12 | let path_str = path.to_str().unwrap(); 13 | ptr::copy_nonoverlapping(path_str.as_c_ptr(), output, path_str.len()); 14 | *result_len = path_str.len(); 15 | } 16 | 17 | #[no_mangle] 18 | pub unsafe extern "C" fn ocall_save_to_memory(data_ptr: *const u8, data_len: usize) -> u64 { 19 | let data = slice::from_raw_parts(data_ptr, data_len).to_vec(); 20 | let ptr = Box::into_raw(Box::new(data.into_boxed_slice())) as *const u8; 21 | ptr as u64 22 | } -------------------------------------------------------------------------------- /enigma-tools-u/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "lib"] 2 | #![warn(unused_extern_crates)] 3 | 4 | extern crate enigma_crypto; 5 | extern crate enigma_types; 6 | #[macro_use] 7 | extern crate failure; 8 | extern crate reqwest; 9 | extern crate serde_json; 10 | extern crate base64; 11 | extern crate openssl; 12 | extern crate rlp; 13 | extern crate rustc_hex as hex; 14 | #[macro_use] 15 | extern crate serde; 16 | // web3 utils 17 | extern crate web3; 18 | // SGX Libraries 19 | extern crate sgx_types; 20 | extern crate sgx_urts; 21 | #[macro_use] 22 | extern crate log; 23 | extern crate log4rs; 24 | 25 | #[macro_use] 26 | extern crate log_derive; 27 | extern crate ethabi; 28 | extern crate ethereum_types; 29 | extern crate tiny_keccak; 30 | 31 | extern crate gethostname; 32 | 33 | pub mod attestation_service; 34 | pub mod common_u; 35 | pub mod esgx; 36 | pub mod web3_utils; 37 | 38 | #[cfg(test)] 39 | mod tests { 40 | #[test] 41 | fn it_works() { 42 | assert_eq!(2 + 2, 4); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /enigma-tools-u/src/tests/web3_tests/deploy_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "ENIGMA_CONTRACT_PATH" : "../app/tests/principal_node/contracts/Enigma.json", 3 | "ENIGMA_TOKEN_CONTRACT_PATH" : "../app/tests/principal_node/contracts/EnigmaToken.json", 4 | "ACCOUNT_ADDRESS" : "627306090abab3a6e1400e9345bc60c78a8bef57", 5 | "URL" : "http://localhost:8545" 6 | } -------------------------------------------------------------------------------- /enigma-tools-u/src/tests/web3_tests/principal_test_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "ENIGMA_CONTRACT_PATH" : "../app/tests/principal_node/contracts/Enigma.json", 3 | "ENIGMA_CONTRACT_REMOTE_PATH" : "", 4 | "ENIGMA_CONTRACT_ADDRESS" : "f25186B5081Ff5cE73482AD761DB0eB0d25abfBF", 5 | "ACCOUNT_ADDRESS" : "627306090abab3a6e1400e9345bc60c78a8bef57", 6 | "TEST_NET" : true, 7 | "WITH_PRIVATE_KEY" : false, 8 | "PRIVATE_KEY" : "", 9 | "URL" : "http://localhost:8545", 10 | "EPOCH_SIZE" : 2, 11 | "POLLING_INTERVAL" : 1, 12 | "SPID" : "B0335FD3BC1CCA8F804EB98A6420592D", 13 | "ATTESTATION_SERVICE_URL" : "https://sgx.enigma.co/api" 14 | } 15 | -------------------------------------------------------------------------------- /enigma-tools-u/src/web3_utils/mod.rs: -------------------------------------------------------------------------------- 1 | mod raw_transaction; 2 | mod contract_ext; 3 | pub mod enigma_contract; 4 | pub mod w3utils; 5 | -------------------------------------------------------------------------------- /enigma-types/Cargo.toml: -------------------------------------------------------------------------------- 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 "] 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"] 25 | -------------------------------------------------------------------------------- /enigma-types/build.rs: -------------------------------------------------------------------------------- 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 | } -------------------------------------------------------------------------------- /enigma-types/src/hash.rs: -------------------------------------------------------------------------------- 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 { 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 | } -------------------------------------------------------------------------------- /enigma-types/src/lib.rs: -------------------------------------------------------------------------------- 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.
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(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 | } 38 | -------------------------------------------------------------------------------- /enigma-types/src/traits.rs: -------------------------------------------------------------------------------- 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 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 | } 46 | -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/contract_with_eth_calls/.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-unknown-unknown" -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/contract_with_eth_calls/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "contract" 3 | version = "0.1.0" 4 | 5 | [dependencies] 6 | eng-wasm = "0.1" 7 | eng-wasm-derive = "0.1" 8 | rustc-hex = "2.0.1" 9 | 10 | [lib] 11 | crate-type = ["cdylib"] 12 | 13 | [profile.release] 14 | panic = "abort" 15 | lto = true 16 | opt-level = "z" 17 | -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/contract_with_eth_calls/Test.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "constant": false, 4 | "inputs": [{"name":"", "type": "uint256"}, {"name": "","type": "address[]"}], 5 | "name": "getBryn", 6 | "outputs": [], 7 | "payable": false, 8 | "stateMutability": "nonpayable", 9 | "type": "function" 10 | }, 11 | { 12 | "constant": true, 13 | "inputs": [{"name": "", "type": "uint256"}], 14 | "name": "record", 15 | "outputs": [], 16 | "payable": false, 17 | "stateMutability": "view", 18 | "type": "function" 19 | } 20 | ] 21 | -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/contract_with_eth_calls/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | extern crate eng_wasm; 4 | extern crate eng_wasm_derive; 5 | extern crate rustc_hex; 6 | 7 | 8 | use eng_wasm::*; 9 | use eng_wasm_derive::pub_interface; 10 | use eng_wasm_derive::eth_contract; 11 | 12 | use eng_wasm::String; 13 | use rustc_hex::ToHex; 14 | 15 | 16 | #[eth_contract("Test.json")] 17 | struct EthContract; 18 | 19 | #[pub_interface] 20 | pub trait ContractInterface{ 21 | fn write(); 22 | fn print_test(x: U256, y: U256); 23 | fn test(); 24 | fn construct(); 25 | fn sum_and_call(x: U256, y: U256, eth_addr: H160) -> U256; 26 | fn get_last_sum() -> U256; 27 | } 28 | 29 | pub struct Contract; 30 | 31 | impl ContractInterface for Contract { 32 | /// Writes value to state and reads it. 33 | /// As a temporary solution the value is converted to a stream of bytes. 34 | /// Later as part of runtime there will be created a macros for writing and reading any type. 35 | fn write() { 36 | let mut a = String::new(); 37 | a.push_str("157"); 38 | let key = "code"; 39 | eprint!("{}", a); 40 | write_state!(key => &a); 41 | let read_val: String = read_state!(key).unwrap(); 42 | 43 | assert_eq!(read_val, a); 44 | } 45 | 46 | fn print_test(x: U256, y: U256) { 47 | eprint!("{:?} {:?}", x.as_u64(), y.as_u64()); 48 | } 49 | 50 | fn test() { 51 | let c = EthContract::new("0x123f681646d4a755815f9cb19e1acc8565a0c2ac"); 52 | c.getBryn(U256::from(1), Vec::new()); 53 | } 54 | 55 | fn construct(){ 56 | let mut a = String::new(); 57 | a.push_str("69"); 58 | let key = "code"; 59 | eprint!("{}", a); 60 | write_state!(key => &a); 61 | let sum: u64 = 12; 62 | write_state!("sum" => sum); 63 | } 64 | 65 | fn sum_and_call(x: U256, y: U256, eth_addr: H160) -> U256 { 66 | let sum: u64 = x.as_u64() + y.as_u64(); 67 | write_state!("code" => sum); 68 | let mut eth_addr_str_0x: String = "0x".to_string(); 69 | let eth_addr_str: String = eth_addr.to_hex(); 70 | eth_addr_str_0x.push_str(ð_addr_str); 71 | let c = EthContract::new(ð_addr_str_0x); 72 | c.record(sum.into()); 73 | sum.into() 74 | } 75 | 76 | fn get_last_sum() -> U256 { 77 | let sum: u64 = read_state!("sum").unwrap_or_default(); 78 | sum.into() 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/encryption/.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-unknown-unknown" -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/encryption/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "contract" 3 | version = "0.1.0" 4 | 5 | [dependencies] 6 | eng-wasm = { path = "../../../eng-wasm" } 7 | eng-wasm-derive = { path = "../../../eng-wasm/derive" } 8 | serde_derive = "1.0.84" 9 | serde = "1.0.84" 10 | enigma-crypto = { path = "../../../enigma-crypto", default-features = false, features = ["asymmetric", "hash"] } 11 | 12 | [lib] 13 | crate-type = ["cdylib"] 14 | 15 | [profile.release] 16 | panic = "abort" 17 | lto = true 18 | opt-level = "z" 19 | -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/encryption/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Rust’s standard library provides a lot of useful functionality, but assumes support for various 2 | // features of its host system: threads, networking, heap allocation, and others. SGX environments 3 | // do not have these features, so we tell Rust that we don’t want to use the standard library 4 | #![no_std] 5 | #![allow(unused_attributes)] 6 | 7 | #[macro_use] 8 | extern crate serde_derive; 9 | extern crate serde; 10 | // The eng_wasm crate allows to use the Enigma runtime, which provides: 11 | // - Read from state read_state!(key) 12 | // - Write to state write_state!(key => value) 13 | // - Print eprint!(...) 14 | extern crate eng_wasm; 15 | 16 | // The eng_wasm_derive crate provides the following 17 | // - Functions exposed by the contract that may be called from the Enigma network 18 | // - Ability to call functions of ethereum contracts from ESC 19 | extern crate eng_wasm_derive; 20 | 21 | // The asymmetric features of enigma_crypto 22 | extern crate enigma_crypto; 23 | 24 | 25 | 26 | // eng_wasm 27 | use eng_wasm::*; 28 | use eng_wasm_derive::pub_interface; 29 | use eng_wasm::{String, Vec}; 30 | use enigma_crypto::asymmetric::KeyPair; 31 | 32 | // State key name "mixer_eth_addr" holding eth address of Mixer contract 33 | //static MIXER_ETH_ADDR: &str = "mixer_eth_addr"; 34 | static ENCRYPTION_KEY: &str = "encryption_key"; 35 | 36 | // For contract-exposed functions, declare such functions under the following public trait: 37 | #[pub_interface] 38 | pub trait ContractInterface { 39 | fn construct(); 40 | fn encrypt_decrypt(plaintext_msg: Vec); 41 | } 42 | 43 | // The implementation of the exported ESC functions should be defined in the trait implementation 44 | // for a new struct. 45 | // #[no_mangle] modifier is required before each function to turn off Rust's name mangling, so that 46 | // it is easier to link to. Sets the symbol for this item to its identifier. 47 | pub struct Contract; 48 | 49 | // Private functions accessible only by the secret contract 50 | impl Contract { 51 | fn get_pkey() -> SymmetricKey { 52 | let key = read_state!(ENCRYPTION_KEY).unwrap(); 53 | let key_pair = KeyPair::from_slice(&key).unwrap(); 54 | let pub_key = key_pair.get_pubkey(); 55 | eprint!("The pub key from the generated key material({:?})", pub_key.to_vec()); 56 | key 57 | } 58 | 59 | fn decrypt(enc_msg: &Vec) -> Vec { 60 | let key = Self::get_pkey(); 61 | eprint!("Decrypting bytes ({:?})", enc_msg); 62 | decrypt(enc_msg, &key) 63 | } 64 | 65 | fn encrypt(plaintext_msg: &Vec) -> Vec { 66 | let key = Self::get_pkey(); 67 | eprint!("Encrypting bytes ({:?})", plaintext_msg); 68 | encrypt(plaintext_msg, &key) 69 | } 70 | } 71 | 72 | impl ContractInterface for Contract { 73 | // Constructor function that takes in VotingETH ethereum contract address 74 | #[no_mangle] 75 | fn construct() { 76 | // Create new random encryption key 77 | let key = generate_key(); 78 | write_state!(ENCRYPTION_KEY => key); 79 | } 80 | 81 | #[no_mangle] 82 | fn encrypt_decrypt(plaintext_msg: Vec) { 83 | let enc_msg = Self::encrypt(&plaintext_msg); 84 | eprint!("The encrypted message: {:?}", enc_msg); 85 | let msg = Self::decrypt(&enc_msg); 86 | eprint!("The decrypted message bytes: {:?}", msg); 87 | if plaintext_msg != msg { 88 | panic!("Mismatching message after decryption"); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/erc20/.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-unknown-unknown" -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/erc20/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "contract" 3 | version = "0.1.0" 4 | 5 | [dependencies] 6 | eng-wasm = "0.1" 7 | eng-wasm-derive = "0.1" 8 | enigma-crypto = { path = "../../../enigma-crypto", default-features = false, features = ["asymmetric", "hash"] } 9 | rustc-hex = "2.0.1" 10 | serde = { version = "1.0", default-features = false, features=["derive"] } 11 | 12 | [lib] 13 | crate-type = ["cdylib"] 14 | 15 | [profile.release] 16 | panic = "abort" 17 | lto = true 18 | opt-level = "z" 19 | -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/factorization/.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-unknown-unknown" -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/factorization/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "contract" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | eng-wasm = "0.1" 8 | eng-wasm-derive = "0.1" 9 | 10 | [lib] 11 | crate-type = ["cdylib"] 12 | 13 | [profile.release] 14 | panic = "abort" 15 | lto = true 16 | opt-level = "z" -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/factorization/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use eng_wasm_derive::pub_interface; 4 | 5 | struct S; 6 | 7 | #[pub_interface] 8 | impl S { 9 | pub fn find_number_of_prime_factors(mut number: u64) -> u64{ 10 | if number == 0 {return 0;} 11 | // The maximal number of 2s that divide `number` 12 | let mut result = number.trailing_zeros() as u64; 13 | let factor_bound = ((number as f64).sqrt().ceil()) as u64; 14 | 15 | number >>= result; 16 | 17 | for i in (3..=factor_bound).step_by(2) { 18 | while number % i == 0 { 19 | result += 1; 20 | number = number / i; 21 | } 22 | } 23 | if number > 1 { 24 | result += 1; 25 | } 26 | result 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/flip_coin/.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-unknown-unknown" -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/flip_coin/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "contract" 3 | version = "0.1.0" 4 | 5 | [dependencies] 6 | eng-wasm = "0.1" 7 | eng-wasm-derive = "0.1" 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | 12 | [profile.release] 13 | panic = "abort" 14 | lto = true 15 | opt-level = "z" 16 | -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/flip_coin/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | extern crate eng_wasm; 4 | extern crate eng_wasm_derive; 5 | 6 | use eng_wasm::*; 7 | use eng_wasm_derive::pub_interface; 8 | 9 | #[pub_interface] 10 | pub trait ContractInterface{ 11 | /// Flipping the coin. Uses true sgx randomness. 12 | fn flip() -> bool; 13 | 14 | /// Player 1 commits to a coin value 15 | fn commit(commitment: bool); 16 | 17 | /// Player 2 guesses the value that player 1 was committed to. The commitment is removed. 18 | /// True is returned on successful guess. 19 | fn guess(guess: bool) -> bool; 20 | } 21 | 22 | const COMMITMENT_KEY: &'static str = "commitment"; 23 | 24 | pub struct Contract; 25 | 26 | impl ContractInterface for Contract { 27 | fn flip() -> bool { 28 | let result: u8 = Rand::gen(); 29 | result % 2 == 1 30 | } 31 | 32 | fn commit(commitment: bool) { 33 | let val: Option = read_state!(COMMITMENT_KEY); 34 | if val.is_none() { 35 | write_state!(COMMITMENT_KEY => commitment); 36 | } 37 | } 38 | 39 | fn guess(guess: bool) -> bool { 40 | let val: Option = remove_from_state!(COMMITMENT_KEY); 41 | match val { 42 | Some(commitment) => commitment == guess, 43 | _ => false 44 | } 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/millionaires_problem_demo/.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-unknown-unknown" -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/millionaires_problem_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "contract" 3 | version = "0.1.0" 4 | authors = ["Aditya Palepu "] 5 | 6 | [dependencies] 7 | eng-wasm = "0.1" 8 | eng-wasm-derive = "0.1" 9 | rustc-hex = "1.0.0" # 2.0.1? 10 | serde_derive = "1.0.84" 11 | serde = "1.0.84" 12 | 13 | [lib] 14 | crate-type = ["cdylib"] 15 | 16 | [profile.release] 17 | panic = "abort" 18 | lto = true 19 | opt-level = "z" -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/millionaires_problem_demo/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Rust’s standard library provides a lot of useful functionality 2 | // but WebAssembly does not support all of it; 3 | // eng_wasm exposes a subset of std. 4 | #![no_std] 5 | 6 | // The eng_wasm crate allows to use the Enigma runtime, which provides: 7 | // reading and writing to state, printing, random and more 8 | extern crate eng_wasm; 9 | 10 | // The eng_wasm_derive crate provides the following: 11 | // * Functions exposed by the contract that may be called from the Enigma network 12 | // * Ability to call functions of Ethereum contracts from ESC 13 | extern crate eng_wasm_derive; 14 | 15 | extern crate serde; 16 | 17 | use eng_wasm::*; 18 | 19 | // The [pub_interface] trait is required for the definition of ESC public functions 20 | use eng_wasm_derive::pub_interface; 21 | 22 | // Enables the serializing and deserializing of custom struct types 23 | use serde::{Serialize, Deserialize}; 24 | 25 | // Const representing the millionaire structs vector to be saved at the contract state 26 | static MILLIONAIRES: &str = "millionaires"; 27 | 28 | // Millionaire struct 29 | #[derive(Serialize, Deserialize)] 30 | pub struct Millionaire { 31 | address: H256, // field containing 32 byte hash type for millionaire's address 32 | net_worth: U256, // field containing 32 byte uint for millionaire's net worth 33 | } 34 | 35 | // Public secret contract function declarations 36 | #[pub_interface] 37 | pub trait ContractInterface{ 38 | fn add_millionaire(address: H256, net_worth: U256); 39 | fn compute_richest() -> H256; 40 | } 41 | 42 | // Public Contract struct which will consist of private and public-facing secret contract functions 43 | pub struct Contract; 44 | 45 | // Private functions accessible only by the secret contract 46 | impl Contract { 47 | // Read secret contract state to obtain vector of Millionaires (or new vector if uninitialized) 48 | fn get_millionaires() -> Vec { 49 | match read_state!(MILLIONAIRES) { 50 | Some(vec) => vec, 51 | None => Vec::new(), 52 | } 53 | } 54 | } 55 | 56 | impl ContractInterface for Contract { 57 | // Add millionaire with 32-byte hash type for address and 32-byte uint for net worth 58 | fn add_millionaire(address: H256, net_worth: U256) { 59 | // Read state to get vector of Millionaires 60 | let mut millionaires = Self::get_millionaires(); 61 | // Append a new Millionaire struct to this vector 62 | millionaires.push(Millionaire { 63 | address, 64 | net_worth, 65 | }); 66 | // Write the updated vector to contract's state 67 | write_state!(MILLIONAIRES => millionaires); 68 | } 69 | 70 | // Compute the richest millionaire by returning the 32-byte hash type for the address 71 | fn compute_richest() -> H256 { 72 | // Read state to get vector of Millionaires and obtain the struct corresponding to the 73 | // richest millionaire by net worth 74 | match Self::get_millionaires().iter().max_by_key(|m| m.net_worth) { 75 | // Return millionaire's address 76 | Some(millionaire) => { 77 | millionaire.address 78 | }, 79 | // Return empty address 80 | None => U256::from(0).into(), 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/simple_addition/.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-unknown-unknown" -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/simple_addition/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "contract " 3 | version = "0.1.0" 4 | 5 | [lib] 6 | crate-type = ["cdylib"] # Create a dynamic library to be loaded from another language 7 | 8 | [dependencies] 9 | eng-wasm = "0.1" 10 | eng-wasm-derive = "0.1" 11 | 12 | [profile.release] # The release profile, used for `cargo build --release`. 13 | panic = "abort" # panic strategy (`-C panic=...`) 14 | lto = true # Link Time Optimization usually reduces size of binaries 15 | # and static libraries. Increases compilation time. 16 | # If true, passes `-C lto` flag to the compiler 17 | opt-level = "z" # controls de --opt-level the compiler build with. 18 | # 'z' reduces size to a minimum 19 | -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/simple_addition/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Rust’s standard library provides a lot of useful functionality, 2 | // but WebAssembly does not support all of it. 3 | // eng_wasm exposes a subset of std. 4 | #![no_std] 5 | 6 | // The eng_wasm crate allows to use the Enigma runtime, which provides: 7 | // manipulating state, creation of random, printing and more 8 | extern crate eng_wasm; 9 | 10 | // The eng_wasm_derive crate provides the following 11 | // - Functions exposed by the contract that may be called from the Enigma network 12 | // - Ability to call functions of ethereum contracts from ESC 13 | extern crate eng_wasm_derive; 14 | 15 | use eng_wasm::*; 16 | 17 | // For contract-exposed functions first include: 18 | use eng_wasm_derive::pub_interface; 19 | 20 | // For contract-exposed functions, declare such functions under the following public trait: 21 | #[pub_interface] 22 | pub trait ContractInterface{ 23 | fn addition(x: U256, y: U256) -> U256 ; 24 | } 25 | 26 | // The implementation of the exported ESC functions should be defined in the trait implementation 27 | // for a new struct. 28 | pub struct Contract; 29 | impl ContractInterface for Contract { 30 | fn addition(x: U256, y: U256) -> U256 { 31 | write_state!("code"=> (x+y).as_u32()); 32 | x + y 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/simple_calculator/.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-unknown-unknown" -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/simple_calculator/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | # must be called contract 3 | name = "contract" 4 | version = "0.1.0" 5 | 6 | [dependencies] 7 | eng-wasm = "0.1" 8 | eng-wasm-derive = "0.1" 9 | 10 | [lib] 11 | crate-type = ["cdylib"] 12 | 13 | [profile.release] 14 | panic = "abort" 15 | lto = true 16 | opt-level = "z" 17 | -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/simple_calculator/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | extern crate eng_wasm; 4 | extern crate eng_wasm_derive; 5 | 6 | use eng_wasm::*; 7 | use eng_wasm_derive::pub_interface; 8 | 9 | #[pub_interface] 10 | pub trait ContractInterface{ 11 | fn add(a: U256, b: U256) -> U256; 12 | fn sub(a: U256, b: U256) -> U256; 13 | fn mul(a: U256, b: U256) -> U256; 14 | fn div(a: U256, b: U256) -> U256; 15 | } 16 | 17 | pub struct Contract; 18 | impl ContractInterface for Contract { 19 | fn add(a: U256, b: U256) -> U256 { 20 | let res = a.checked_add(b); 21 | match res { 22 | Some(r) => r, 23 | None => panic!("addition overflow"), 24 | } 25 | } 26 | 27 | fn sub(a: U256, b: U256) -> U256 { 28 | let res = a.checked_sub(b); 29 | match res { 30 | Some(r) => r, 31 | None => panic!("subtraction overflow"), 32 | } 33 | } 34 | 35 | fn mul(a: U256, b: U256) -> U256 { 36 | let res = a.checked_mul(b); 37 | match res { 38 | Some(r) => r, 39 | None => panic!("multiple overflow"), 40 | } 41 | } 42 | 43 | fn div(a: U256, b: U256) -> U256 { 44 | let res = a.checked_div(b); 45 | match res { 46 | Some(r) => r, 47 | None => panic!("division by zero"), 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/simplest/.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-unknown-unknown" -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/simplest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "contract" 3 | version = "0.1.0" 4 | 5 | [dependencies] 6 | eng-wasm = "0.1" 7 | eng-wasm-derive = "0.1" 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | 12 | [profile.release] 13 | panic = "abort" 14 | lto = true 15 | opt-level = "z" 16 | -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/simplest/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | extern crate eng_wasm; 4 | extern crate eng_wasm_derive; 5 | 6 | use eng_wasm::*; 7 | use eng_wasm_derive::pub_interface; 8 | 9 | #[pub_interface] 10 | pub trait ContractInterface{ 11 | fn write() -> Vec; 12 | fn check_address(addr: H256) -> H256; 13 | fn check_addresses(addr1: H256, addr2: H256) -> Vec; 14 | fn choose_rand_color() -> Vec; 15 | fn get_scrambled_vec(); 16 | fn addition(x: U256, y: U256) -> U256; 17 | fn get_last_sum() -> U256; 18 | fn print_test(x: U256, y: U256); 19 | fn dynamic_types(bytes_arr: Vec>, string_arr: Vec, fixed_arr: Vec); 20 | fn construct(param: U256); 21 | } 22 | 23 | pub struct Contract; 24 | 25 | impl Contract { 26 | fn gen_loc(len: usize) -> usize { 27 | assert!(len > 0); 28 | let rand: u32 = Rand::gen(); 29 | rand as usize % len 30 | } 31 | /// gets an a slice containing any type. running 32 | /// on a loop in the length of (len(slice) - 1) 33 | /// it swaps the last element with a random 34 | /// location in the slice and reduces the length. 35 | fn shuffle(values: &mut [T]) { 36 | let mut i = values.len(); 37 | while i >= 2 { 38 | i -= 1; 39 | values.swap(i, Contract::gen_loc(i + 1)); 40 | } 41 | } 42 | } 43 | 44 | impl ContractInterface for Contract { 45 | /// Writes value to state and reads it. 46 | /// As a temporary solution the value is converted to a stream of bytes. 47 | /// Later as part of runtime there will be created a macros for writing and reading any type. 48 | fn write() -> Vec { 49 | let mut a = String::new(); 50 | a.push_str("157"); 51 | let key = "code"; 52 | write_state!(key => &a); 53 | let read_val: String = read_state!(key).unwrap_or_default(); 54 | 55 | assert_eq!(read_val, a); 56 | read_val.as_bytes().to_vec() 57 | } 58 | 59 | fn check_address(addr: H256) -> H256{ 60 | write_state!("addr" => addr); 61 | let read_val: H256 = read_state!("addr").unwrap_or_default(); 62 | assert_eq!(read_val, addr); 63 | read_val 64 | } 65 | fn dynamic_types(bytes_arr: Vec>, string_arr: Vec, fixed_arr: Vec) { 66 | eprint!("array of bytes: {:?}",bytes_arr); 67 | eprint!("array of String: {:?}",string_arr); 68 | eprint!("array of H256: {:?}",fixed_arr); 69 | } 70 | 71 | fn check_addresses(addr1: H256, addr2: H256) -> Vec { 72 | write_state!("addr1" => addr1); 73 | write_state!("addr2" => addr2); 74 | 75 | let read_addr1: H256 = read_state!("addr1").unwrap_or_default(); 76 | let read_addr2: H256 = read_state!("addr2").unwrap_or_default(); 77 | 78 | assert_eq!(read_addr1, addr1); 79 | assert_eq!(read_addr2, addr2); 80 | let mut ret = Vec::with_capacity(2); 81 | ret.push(read_addr1); 82 | ret.push(read_addr2); 83 | ret 84 | } 85 | 86 | // tests the random service 87 | fn choose_rand_color() -> Vec { 88 | let mut colors = Vec::new(); 89 | colors.extend(["green", "yellow", "red", "blue", "white", "black", "orange", "purple"].iter().cloned()); 90 | let random: u8 = Rand::gen(); 91 | 92 | let rng_rand = (random as usize) % colors.len(); 93 | write_state!("color" => colors[rng_rand]); 94 | let color : String = read_state!("color").unwrap_or_default(); 95 | color.as_bytes().to_vec() 96 | } 97 | 98 | // tests the shuffle service on a simple array 99 | fn get_scrambled_vec() { 100 | let mut nums: [u8; 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 101 | Self::shuffle(&mut nums); 102 | unsafe {external::ret(nums.as_ptr(), nums.len() as u32)}; 103 | } 104 | 105 | fn addition(x: U256, y: U256) -> U256 { 106 | let sum: u64 = x.as_u64() + y.as_u64(); 107 | write_state!("curr_sum" => sum); 108 | sum.into() 109 | } 110 | 111 | fn get_last_sum() -> U256 { 112 | let sum: u64 = read_state!("curr_sum").unwrap_or_default(); 113 | sum.into() 114 | } 115 | 116 | fn print_test(x: U256, y: U256) { 117 | eprint!("{:?} {:?}", x.as_u64(), y.as_u64()); 118 | } 119 | 120 | fn construct(param: U256){ 121 | write_state!("1" => param.as_u64()); 122 | } 123 | } -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/voting_demo/.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-unknown-unknown" 3 | -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/voting_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "contract" 3 | version = "0.1.0" 4 | authors = ["Aditya Palepu "] 5 | 6 | [dependencies] 7 | eng-wasm = "0.1" 8 | eng-wasm-derive = "0.1" 9 | rustc-hex = "2.0.1" 10 | serde_derive = "1.0.84" 11 | serde = "1.0.84" 12 | 13 | [lib] 14 | crate-type = ["cdylib"] 15 | 16 | [profile.release] 17 | panic = "abort" 18 | lto = true 19 | opt-level = "z" 20 | -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/voting_demo/VotingETH.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "constant": true, 4 | "inputs": [ 5 | { 6 | "name": "", 7 | "type": "uint256" 8 | } 9 | ], 10 | "name": "polls", 11 | "outputs": [ 12 | { 13 | "name": "creator", 14 | "type": "address" 15 | }, 16 | { 17 | "name": "quorumPercentage", 18 | "type": "uint256" 19 | }, 20 | { 21 | "name": "expirationTime", 22 | "type": "uint256" 23 | }, 24 | { 25 | "name": "status", 26 | "type": "uint8" 27 | }, 28 | { 29 | "name": "description", 30 | "type": "string" 31 | } 32 | ], 33 | "payable": false, 34 | "stateMutability": "view", 35 | "type": "function", 36 | "signature": "0xac2f0074" 37 | }, 38 | { 39 | "inputs": [], 40 | "payable": false, 41 | "stateMutability": "nonpayable", 42 | "type": "constructor", 43 | "signature": "constructor" 44 | }, 45 | { 46 | "constant": false, 47 | "inputs": [ 48 | { 49 | "name": "_quorumPercentage", 50 | "type": "uint256" 51 | }, 52 | { 53 | "name": "_description", 54 | "type": "string" 55 | }, 56 | { 57 | "name": "_pollLength", 58 | "type": "uint256" 59 | } 60 | ], 61 | "name": "createPoll", 62 | "outputs": [], 63 | "payable": false, 64 | "stateMutability": "nonpayable", 65 | "type": "function", 66 | "signature": "0x236e1b93" 67 | }, 68 | { 69 | "constant": false, 70 | "inputs": [ 71 | { 72 | "name": "_pollId", 73 | "type": "uint256" 74 | } 75 | ], 76 | "name": "validateCastVote", 77 | "outputs": [], 78 | "payable": false, 79 | "stateMutability": "nonpayable", 80 | "type": "function", 81 | "signature": "0x40a7dba9" 82 | }, 83 | { 84 | "constant": false, 85 | "inputs": [ 86 | { 87 | "name": "_pollId", 88 | "type": "uint256" 89 | }, 90 | { 91 | "name": "_talliedQuorum", 92 | "type": "uint256" 93 | } 94 | ], 95 | "name": "validateTallyPoll", 96 | "outputs": [], 97 | "payable": false, 98 | "stateMutability": "nonpayable", 99 | "type": "function", 100 | "signature": "0x796f5606" 101 | } 102 | ] 103 | -------------------------------------------------------------------------------- /examples/eng_wasm_contracts/voting_demo/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | extern crate eng_wasm; 4 | extern crate eng_wasm_derive; 5 | extern crate rustc_hex; 6 | extern crate serde_derive; 7 | extern crate serde; 8 | 9 | use eng_wasm::*; 10 | use eng_wasm_derive::pub_interface; 11 | use eng_wasm_derive::eth_contract; 12 | use eng_wasm::String; 13 | use std::collections::HashMap; 14 | use rustc_hex::ToHex; 15 | 16 | // VotingETH contract abi 17 | #[eth_contract("VotingETH.json")] 18 | struct EthContract; 19 | 20 | // State key name "polls" holding a vector of Poll structs 21 | static POLLS: &str = "polls"; 22 | // State key name "voting_eth_addr" holding eth address of VotingETH contract 23 | static VOTING_ETH_ADDR: &str = "voting_eth_addr"; 24 | 25 | // Public-facing secret contract function declarations 26 | #[pub_interface] 27 | pub trait ContractInterface{ 28 | fn construct(voting_eth_addr: H160); 29 | fn cast_vote(poll_id: U256, voter: H256, vote: U256); 30 | fn tally_poll(poll_id: U256); 31 | } 32 | 33 | pub struct Contract; 34 | 35 | // Private functions accessible only by the secret contract 36 | impl Contract { 37 | // Read secret contract state to obtain vector of Poll structs (or new vector if uninitialized) 38 | fn get_polls() -> HashMap> { 39 | read_state!(POLLS).unwrap_or_default() 40 | } 41 | 42 | // Read voting address of VotingETH contract 43 | fn get_voting_eth_addr() -> String { 44 | read_state!(VOTING_ETH_ADDR).unwrap_or_default() 45 | } 46 | } 47 | 48 | impl ContractInterface for Contract { 49 | // Constructor function that takes in VotingETH ethereum contract address 50 | fn construct(voting_eth_addr: H160) { 51 | let voting_eth_addr_str: String = voting_eth_addr.to_hex(); 52 | write_state!(VOTING_ETH_ADDR => voting_eth_addr_str); 53 | } 54 | 55 | // Cast vote function that takes poll ID, voter address, and vote - calls back to ETH 56 | fn cast_vote(poll_id: U256, voter: H256, vote: U256) { 57 | let mut polls = Self::get_polls(); 58 | { 59 | let voter_info = polls.entry(poll_id.as_u64()).or_insert_with(HashMap::new); 60 | let key: String = voter.to_hex(); 61 | assert!(!(*voter_info).contains_key(&key), "user has already voted in poll"); 62 | (*voter_info).insert(key, vote); 63 | } 64 | write_state!(POLLS => polls); 65 | let voting_eth_addr: String = Self::get_voting_eth_addr(); 66 | let c = EthContract::new(&voting_eth_addr); 67 | c.validateCastVote(poll_id); 68 | } 69 | 70 | // Tally poll function that takes poll ID - calls back to ETH 71 | fn tally_poll(poll_id: U256) { 72 | let polls = Self::get_polls(); 73 | let mut tallied_quorum: U256 = U256::zero(); 74 | if let Some(voter_info) = polls.get(&poll_id.as_u64()) { 75 | for val in voter_info.values() { 76 | tallied_quorum = tallied_quorum.checked_add(*val).unwrap(); 77 | } 78 | tallied_quorum = tallied_quorum.checked_mul(100.into()).unwrap().checked_div(voter_info.len().into()).unwrap() 79 | } 80 | let voting_eth_addr: String = Self::get_voting_eth_addr(); 81 | let c = EthContract::new(&voting_eth_addr); 82 | c.validateTallyPoll(poll_id, tallied_quorum); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /rust-toolchain: -------------------------------------------------------------------------------- 1 | nightly-2019-08-01 --------------------------------------------------------------------------------