-
Notifications
You must be signed in to change notification settings - Fork 126
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1416 from GaloisInc/ffi-aes-ni
AES-NI version of SuiteB module using FFI
- Loading branch information
Showing
15 changed files
with
5,448 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
*.so | ||
*.dylib |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
SHELL = /bin/bash | ||
CFLAGS = -O3 -Wall -Wextra -Werror | ||
|
||
.PHONY: test perf-test perf-bench clean | ||
|
||
ifeq ($(shell uname -m),x86_64) | ||
|
||
ifdef PORTABLE | ||
CFLAGS += -maes -mssse3 | ||
else | ||
CFLAGS += -march=native | ||
endif | ||
|
||
endif | ||
|
||
ifeq ($(shell uname),Darwin) | ||
|
||
SO = SuiteB_FFI.dylib | ||
TEST_OUT_EXT = .stdout.darwin | ||
|
||
$(SO): SuiteB_FFI.c | ||
$(CC) $(CFLAGS) -dynamiclib $< -o $@ | ||
|
||
else | ||
|
||
SO = SuiteB_FFI.so | ||
TEST_OUT_EXT = .stdout | ||
|
||
$(SO): SuiteB_FFI.c | ||
$(CC) $(CFLAGS) -fPIC -shared $< -o $@ | ||
|
||
endif | ||
|
||
test: $(SO) | ||
diff tests/aes-vectors.icry$(TEST_OUT_EXT) <(cryptol -b tests/aes-vectors.icry) | ||
diff tests/aes-mct-ecb.icry$(TEST_OUT_EXT) <(cryptol -b tests/aes-mct-ecb.icry) | ||
|
||
perf-test: $(SO) | ||
time cryptol -b tests/aes-mct-ecb.icry | ||
time cryptol -b ../../tests/suiteb/aes-mct-ecb.icry | ||
|
||
perf-bench: $(SO) | ||
cryptol -b perf-bench.icry | ||
|
||
clean: | ||
rm $(SO) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
# `SuiteB_FFI` | ||
|
||
`SuiteB_FFI` is a drop-in replacement for the builtin `SuiteB` module, using the | ||
FFI to implement AES operations with hardware AES-NI instructions when | ||
available, and falling back to the `SuiteB` software implementation in Cryptol | ||
and Haskell otherwise. | ||
|
||
When AES-NI is available, it is several times faster than `SuiteB`; on a Linux | ||
machine with an Intel i7-10510U it is about 5.5x faster. Note that AES-NI is | ||
only available on modern x86-64 processors, but you could modify this to support | ||
similar instructions for other architectures or bind to a portable C library | ||
instead. | ||
|
||
The actual AES implementation is written with x86-64 intrinsics in C and based | ||
on Intel's [AES-NI | ||
whitepaper](https://www.intel.com/content/dam/doc/white-paper/advanced-encryption-standard-new-instructions-set-paper.pdf) | ||
but with modifications to support how the `SuiteB` module's API is structured. | ||
In particular, the representation of round keys as `[4][32]` in `SuiteB` means | ||
that we need to do a byte swap every time we access memory to correct for | ||
endianness. | ||
|
||
Maintaining compatibility with `SuiteB` actually severely limits the speedup | ||
that we can achieve: right now about 96% of the time spent calling the encrypt | ||
function in Cryptol is spent doing the Cryptol evaluation surrounding the FFI | ||
call and the actual AES computation only takes up less than 4% of the total | ||
time. This is because the encrypt function in `SuiteB` only encrypts one block, | ||
so if you were to create a foreign function that encrypted many blocks at once, | ||
the overhead would be much smaller relative to the work done in the foreign | ||
function and you would achieve a much greater speedup. | ||
|
||
The implementation passes the AES tests from the Cryptol SuiteB test suite | ||
(`aes-mct-ecb` and `aes-vectors`) but has not been verified beyond that. | ||
|
||
## Usage | ||
|
||
Run `make` to build the C code. The code checks for hardware AES-NI support at | ||
runtime with `cpuid` when any AES function is first used. On non-x86-64 | ||
platforms, running `make` will build a dummy implementation that always falls | ||
back to software `SuiteB`. On x86-64, `make` uses `-march=native` to build an | ||
optimized version for running on the current machine. To build a (somewhat) | ||
portable version that will run on any x86-64 machine with AES-NI and SSSE3, use | ||
`make PORTABLE=1`. Once it is built, loading the `SuiteB_FFI` Cryptol module | ||
will automatically load the shared library. | ||
|
||
Run `make test` to test correctness. This runs the tests in the `tests/` | ||
directory which are copied from Cryptol's `/tests/suiteb/` but using the | ||
`SuiteB_FFI` module instead of `SuiteB`. | ||
|
||
Run `make perf-test` to test performance on the `aes-mct-ecb` test. This prints | ||
out the time it takes to run the test with the FFI version and the Cryptol | ||
version. | ||
|
||
Run `make perf-bench` to test the performance of the individual AES-128 | ||
functions with Cryptol's `:time` benchmarking command. This prints out the | ||
benchmarked time for the key expansion and encryption functions for both | ||
implementations, and the speedup in both cases. | ||
|
||
Run `make clean` to delete generated files. |
Oops, something went wrong.