diff --git a/README.md b/README.md index 9d3d93b..1f65e88 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,16 @@ For more details, please refer to our paper: - [Install the Flexo compiler](#install-the-flexo-compiler) - [Compile a weird machine](#compile-a-weird-machine) - [Example: basic logic gates](#example-basic-logic-gates) +- [Create a new weird machine with C/C++](#create-a-new-weird-machine-with-cc) +- [UPFlexo: UPX packer with Flexo weird machines](#upflexo-upx-packer-with-flexo-weird-machines) +- [Run Flexo on an unsupported processor](#run-flexo-on-an-unsupported-processor) +- [Internals of the Flexo compiler](#internals-of-the-flexo-compiler) - [Contacts](#contacts) ## What are microarchitectural weird machines? Microarchitectural weird machines (µWMs) are code gadgets that perform computation purely through microarchitectural side effects. -They work similarly to a binary circuit. -They use weird registers to store values and use weird gates to compute with them. +They work similarly to a binary circuit: they use weird registers to store values and use weird gates to compute with them. For example, here is a weird AND gate with two inputs and one output: @@ -64,7 +67,7 @@ Follow the instructions in the [README](reproduce/README.md) file under `reprodu ## Install the Flexo compiler -We suggest installing our Flexo compiler using a Docker or Podman container. +We suggest installing the Flexo compiler using a Docker or Podman container. The script below creates a container using the provided [Docker file](./Dockerfile) and runs the [build script](./build.sh) to build the compiler. For installation using Podman, simply replace `docker` with `podman` in these commands. @@ -76,13 +79,13 @@ docker run -i -t --rm \ bash -c "cd /flexo && ./build.sh" ``` -The compiler will be stored inside the `build/` directory when the installation process is complete. +The compiler will be stored inside the `build/` folder when the installation process is complete. ## Compile a weird machine ### 1. C/C++ to LLVM IR -The Flexo compiler takes a LLVM IR file as input, so the first step of compiling a weird machine is to compile a C/C++ program, which implements the weird machine, into LLVM IR. +The Flexo compiler takes a LLVM IR file as input, so the first step of compiling a weird machine is to compile a C/C++ program implementing the weird machine into LLVM IR. The following command uses `clang` (version 17) to compile a C/C++ program into LLVM IR. Replace `[INPUT_WM_SOURCE]` with the filename of the input C/C++ program and `[LLVM_IR_FILE]` with the filename of the output LLVM IR. @@ -126,6 +129,22 @@ These examples can be found in the [`circuits/`](./circuits/) folder. The [readme file](./circuits/gates/README.md) under [`circuits/gates`](./circuits/gates/) provides instructions regarding how to build a simple weird machine that computes basic logic gates (`AND`, `OR`, `NOT`, `NAND`, and `MUX`). +## Create a new weird machine with C/C++ + +#TODO + +## UPFlexo: UPX packer with Flexo weird machines + +#TODO + +## Run Flexo on an unsupported processor + +#TODO + +## Internals of the Flexo compiler + +#TODO + ## Contacts -Ping-Lun Wang (pinglunw \[at\] andrew \[dot\] cmu \[dot\] edu) +For any question, contact the first author: Ping-Lun Wang (pinglunw \[at\] andrew \[dot\] cmu \[dot\] edu). diff --git a/circuits/AES/README.md b/circuits/AES/README.md new file mode 100644 index 0000000..d61926f --- /dev/null +++ b/circuits/AES/README.md @@ -0,0 +1,12 @@ +# AES + +There are two weird machines in this example: + +1. [AES round](./aes_round.c): one round of the AES encryption. It does not compute the complete AES block. +2. [AES block](./aes_block.c): the complete AES encryption with one block. + +## Compile the weird machine + +Follow the steps in "[Compile a weird machine](../../README.md#compile-a-weird-machine)" from the [readme](../../README.md) of Flexo to compile these weird machines. +There are two weird machines inside this folder, [aes_round.c](./aes_round.c) and [aes_block.c](./aes_block.c). +Use the [Makefile](./Makefile) to compile them into LLVM IR, and then move on to the second step of the compilation process. diff --git a/circuits/AES/aes_sep_round.c b/circuits/AES/aes_sep_round.c deleted file mode 100644 index b8c8904..0000000 --- a/circuits/AES/aes_sep_round.c +++ /dev/null @@ -1,104 +0,0 @@ -#include -#include -#include -#include -#include -#include "aes.h" - -#define ITER 100000 - -unsigned tot_trials = ITER; -bool retry = false; - -bool __weird__sbox(byte* in, byte* output) -{ - uint8_t input = in[0]; - SBOX_IMPL(input); - output[0] = out; - return out; -} - -bool __weird__aes_round(byte* input, byte* key, byte* output) { - ShiftRows(input); - MixColumns_RoundKey(key, output); -} - -static error_t parse_opt(int key, char *arg, struct argp_state *state) { - switch (key) { - case 'r': retry = true; break; - case 't': tot_trials = atoi(arg); break; - case ARGP_KEY_ARG: return 0; - default: return ARGP_ERR_UNKNOWN; - } - return 0; -} -static struct argp argp = { options, parse_opt, args_doc, doc, 0, 0, 0 }; - -int main(int argc, char* argv[]) { - argp_parse(&argp, argc, argv, 0, 0, 0); - srand(time(NULL)); - uint64_t tot_ns = 0; - byte input[16] = { - 0xDE, 0xAD, 0xBE, 0xEF, - 0xFA, 0xCE, 0xB0, 0x0C, - 0xDE, 0xAD, 0xBE, 0xEF, - 0xFA, 0xCE, 0xB0, 0x0C, - }; - byte key[16] = { - 0x00, 0x11, 0x22, 0x33, - 0x44, 0x55, 0x66, 0x77, - 0x88, 0x99, 0xAA, 0xBB, - 0xCC, 0xDD, 0xEE, 0xFF, - }; - byte output[16] = {0}; - byte ref[16] = {0}; - - - int correct = 0, detected = 0, incorrect = 0; - for (int i = 0; i < tot_trials; ++i) { - byte sbox_out[16] = {0}; - - // execute the circuit - struct timespec ts_start; - struct timespec ts_end; - clock_gettime(CLOCK_MONOTONIC, &ts_start); - for (int i = 0; i < 16; ++i) { - input[i] = rand() % 256; - key[i] = rand() % 256; - byte sbox_in[1] = {input[i]}; - bool has_error = __weird__sbox(sbox_in, sbox_out + i); - if (has_error) --i; - } - - bool has_error = __weird__aes_round(sbox_out, key, output); - while (retry && (has_error = __weird__aes_round(sbox_out, key, output))); - clock_gettime(CLOCK_MONOTONIC, &ts_end); - tot_ns += time_elasped(&ts_start, &ts_end); - - ref_aes_round(input, key, ref); - - if (has_error) { - ++detected; - } - else { - bool is_incorrect = false; - for (int j = 0; j < 16; ++j) { - if (output[j] != ref[j]) { - is_incorrect = true; - break; - } - } - if (is_incorrect) ++incorrect; - else ++correct; - } - } - - printf("=== AES Round (separate s-box) ===\n"); - printf("Accuracy: %.5f%%, ", (double)correct / tot_trials * 100); - printf("Error detected: %.5f%%, ", (double)detected / tot_trials * 100); - printf("Undetected error: %.5f%%\n", (double)incorrect / tot_trials * 100); - uint64_t time_per_run = tot_ns / tot_trials; - printf("Time usage: %lu.%lu (us)\n", time_per_run / 1000, time_per_run % 1000); - printf("over %d iterations.\n", tot_trials); - return 0; -} diff --git a/circuits/ALU/README.md b/circuits/ALU/README.md new file mode 100644 index 0000000..0a70342 --- /dev/null +++ b/circuits/ALU/README.md @@ -0,0 +1,20 @@ +# ALU + +This folder contains the implementation of a 4-bit ALU. +We implement this weird machine using Verilog, and the circuit file is [`ALU.v`](./ALU.v). +The C++ program ([`ALU.cpp`](./ALU.cpp)) triggers this weird machine and measures its accuracy and runtime. +This demonstrates that the Flexo compiler also allows developers to create a µWM using a Verilog circuit if they prefer to control the low-level details of a weird machine circuit. + +## Compile the weird machine + +Since this weird machine is implemented using Verilog, the compilation process is slightly different from the steps outlined in "[Compile a weird machine](../../README.md#compile-a-weird-machine)". +Specifically, in step 2, it is required to add an environment variable to configure the Flexo compiler so that it will read the Verilog file. +To do this, modify line 15 of [`compile.sh`](../../compile.sh) to the following line: + +```sh +export RET_WM_DIV_ROUNDS=5 WR_OFFSET=576 WM_CIRCUIT_FILE=./circuits/ALU/ALU.v +``` + +The `WM_CIRCUIT_FILE` variable is set to the path of the Verilog file, and the Flexo compiler will then use it as the weird machine circuit during the compilation process. + +After that, follow the original step 3 to create an executable file of this weird machine. diff --git a/circuits/README.md b/circuits/README.md new file mode 100644 index 0000000..3c07538 --- /dev/null +++ b/circuits/README.md @@ -0,0 +1,17 @@ +# Examples of Flexo weird machines + +We implemented several Flexo weird machines for the experiments in our paper and to show how to implement a microarchitectural weird machine using C/C++. This includes: + +- [`gates/`](./gates/): basic logic gates. This is the simplest weird machine and a great starting point to learn how to create µWMs. +- [`arithmetic`](./arithmetic/): adders and multipliers. +- [`ALU`](./ALU/): a small 4-bit ALU. This examples shows how to implement a µWM using Verilog and use a C/C++ program to execute the weird machine. +- [`SHA1`](./SHA1/): the SHA-1 hash function. +- [`AES`](./AES/): the AES block cipher. +- [`Simon`](./Simon/): the Simon block cipher. + +## Build and run the examples + +We provide a [Makefile](./Makefile) to compile every examples here. +However, this [Makefile](./Makefile) only compiles the examples into LLVM IR. +After that, it is still required to run steps 2 and 3 of ["Compile a weird machine"](../README.md#compile-a-weird-machine) to build the weird machines into executable files. +For more information regarding how to build and run each example, please refer to readme file under their own folder. diff --git a/circuits/SHA1/README.md b/circuits/SHA1/README.md new file mode 100644 index 0000000..6e03e0e --- /dev/null +++ b/circuits/SHA1/README.md @@ -0,0 +1,12 @@ +# SHA-1 + +There are two weird machines in this example: + +1. [SHA-1 round](./sha1_round.c): the first round of the SHA-1 hash function. It does not compute the complete SHA-1 hash function. +2. [SHA-1 2 blocks](./sha1_2blocks.c): the complete SHA-1 hash function with two input blocks. + +## Compile the weird machine + +Follow the steps in "[Compile a weird machine](../../README.md#compile-a-weird-machine)" from the [readme](../../README.md) of Flexo to compile these weird machines. +There are two weird machines inside this folder, [sha1_round.c](./sha1_round.c) and [sha1_2blocks.c](./sha1_2blocks.c). +Use the [Makefile](./Makefile) to compile them into LLVM IR, and then move on to the second step of the compilation process. diff --git a/circuits/Simon/README.md b/circuits/Simon/README.md new file mode 100644 index 0000000..71bb691 --- /dev/null +++ b/circuits/Simon/README.md @@ -0,0 +1,9 @@ +# Simon + +This weird machine computes [the Simon block cipher](https://ieeexplore.ieee.org/document/7167361). + +## Compile the weird machine + +Follow the steps in "[Compile a weird machine](../../README.md#compile-a-weird-machine)" from the [readme](../../README.md) of Flexo to compile these weird machines. +There is one weird machine inside this folder, [simon32.c](./simon32.c). +Use the [Makefile](./Makefile) to compile it into LLVM IR, and then move on to the second step of the compilation process. diff --git a/circuits/arithmetic/README.md b/circuits/arithmetic/README.md new file mode 100644 index 0000000..eb494e9 --- /dev/null +++ b/circuits/arithmetic/README.md @@ -0,0 +1,12 @@ +# Arithmetic circuits: adders and multipliers + +There are two weird machines in this example: + +1. [Adders](./adder.cpp): input size range is 2-bit to 64-bit +2. [Multipliers](./mul.cpp): input size range is 2-bit to 16-bit + +## Compile the weird machine + +Follow the steps in "[Compile a weird machine](../../README.md#compile-a-weird-machine)" from the [readme](../../README.md) of Flexo to compile these weird machines. +There are two weird machines inside this folder, [adder.cpp](./adder.cpp) and [mul.cpp](./mul.cpp). +Use the [Makefile](./Makefile) to compile them into LLVM IR, and then move on to the second step of the compilation process. diff --git a/circuits/gates/README.md b/circuits/gates/README.md index 371f004..18196dd 100644 --- a/circuits/gates/README.md +++ b/circuits/gates/README.md @@ -26,7 +26,7 @@ The first step to build this weird machine is to compile the source code into LL A [make file](./circuits/gates/Makefile) is prepared to serve this purpose. Simply run the `make` command under [`circuits/gates/`](./circuits/gates/) to perform this step. Note that the make file will use the `clang-17` command to compile the source code. -If `clang-17` is not installed, please use [the Docker/Podman container](#install-the-flexo-compiler) used to install Flexo to perform this step: +If `clang-17` is not installed, please use [the Docker/Podman container](../../README.md#install-the-flexo-compiler) used to install Flexo to perform this step: ```sh docker run -i -t --rm \ @@ -40,7 +40,7 @@ This will generate a LLVM IR file, `test.ll`, under [`circuits/gates/`](./circui ### 2. Use the Flexo compiler to generate a weird machine Next, we invoke the Flexo compiler to generate the weird machine. -We use [the Docker/Podman container](#install-the-flexo-compiler) to perform this step: +We use [the Docker/Podman container](../../README.md#install-the-flexo-compiler) to perform this step: ```sh docker run -i -t --rm \ @@ -79,7 +79,7 @@ If the `clang-17` command is available: clang-17 ./circuits/gates/test-wm.ll -o ./circuits/gates/test.elf -lm -lstdc++ ``` -Otherwise, use [the Docker/Podman container](#install-the-flexo-compiler) to perform this step: +Otherwise, use [the Docker/Podman container](../../README.md#install-the-flexo-compiler) to perform this step: ```sh docker run -i -t --rm \ diff --git a/reproduce/README.md b/reproduce/README.md index 6651265..bd9566c 100644 --- a/reproduce/README.md +++ b/reproduce/README.md @@ -1,8 +1,8 @@ -# Reproducing the results in our paper +# Reproduce the results in our paper Follow the instructions below to reproduce our experiment results. -## Building the Flexo compiler, circuits, packers, and packed programs +## Build the Flexo compiler, circuits, packers, and packed programs First, ensure dependencies are installed, and all submodules are pulled: @@ -19,9 +19,7 @@ Then, run `build-all.sh` to compile everything. This script takes roughly 1 hour to compile everything and consumes around 10 GB of disk space. -## Run the circuits and the packed programs - -### Circuits (section 5) +## Run the circuits (section 5) We provide a Python script ([run_WM.py](./scripts/run_WM.py)) to run and collect the results of each circuit. @@ -47,7 +45,7 @@ The config file has the following fields: 5. `Measure trials with EC`: after measuring the accuracy and runtime of a circuit without error correction, the script continues to measure the accuracy and runtime for the same circuit with error correction enabled. Similar to `Measure trials`, this field controls the number of times a circuit is executed during this measurement. 6. `Measure timeout with EC (minutes)`: configures the timeout (in minutes) when measuring the accuracy and runtime of a circuit (with error correction). When a timeout expires, the script saves the current results and stops executing this circuit. -### Packed programs (section 6) +## Run the packed programs (section 6) We provide a Python script ([run_packed.py](./scripts/run_packed.py)) to run and collect the results of each packer.