From cd482d69e944f890f278dec7bf35725ea214380e Mon Sep 17 00:00:00 2001 From: Ben Marshall Date: Thu, 8 Oct 2020 16:36:55 +0100 Subject: [PATCH] Working on per-instruction KAT generation. #27 - Simple C program which feeds random inputs into each instruction and records the result. - Can be used later to check different simulators work correctly, and to generate compliance tests. On branch dev/next-release Your branch is ahead of 'origin/dev/next-release' by 1 commit. (use "git push" to publish your local commits) Changes to be committed: modified: Makefile modified: benchmarks/Makefile modified: benchmarks/common.mk new file: benchmarks/kat-gen/Makefile.in new file: benchmarks/kat-gen/README.md new file: benchmarks/kat-gen/kat-gen.c modified: benchmarks/share/riscv-crypto-intrinsics.h Changes not staged for commit: modified: extern/riscv-gnu-toolchain (modified content) modified: extern/riscv-isa-sim (modified content) --- Makefile | 11 -- benchmarks/Makefile | 1 + benchmarks/common.mk | 4 +- benchmarks/kat-gen/Makefile.in | 8 + benchmarks/kat-gen/README.md | 7 + benchmarks/kat-gen/kat-gen.c | 218 +++++++++++++++++++++ benchmarks/share/riscv-crypto-intrinsics.h | 8 +- 7 files changed, 241 insertions(+), 16 deletions(-) create mode 100644 benchmarks/kat-gen/Makefile.in create mode 100644 benchmarks/kat-gen/README.md create mode 100644 benchmarks/kat-gen/kat-gen.c diff --git a/Makefile b/Makefile index 6fcf22e7..3f27a622 100644 --- a/Makefile +++ b/Makefile @@ -7,17 +7,6 @@ spec: $(MAKE) -C $(REPO_HOME)/doc/ specs -tests-assembler: - $(MAKE) -C $(REPO_HOME)/tests/assembler all - -tests-compiler: - $(MAKE) -C $(REPO_HOME)/tests/compiler all - -tests-kat: - $(MAKE) -C $(REPO_HOME)/tests/kat all - -tests-all: tests-assembler tests-compiler tests-kat - OPCODES_SPEC_SCALAR = $(REPO_HOME)/tools/opcodes-crypto-scalar OPCODES_SPEC_VECTOR = $(REPO_HOME)/tools/opcodes-crypto-vector diff --git a/benchmarks/Makefile b/benchmarks/Makefile index b17d74f4..83c0b6b2 100644 --- a/benchmarks/Makefile +++ b/benchmarks/Makefile @@ -43,6 +43,7 @@ include sha3/zscrypto_rv64/Makefile.in include permutation/Makefile.in include test/Makefile.in +include kat-gen/Makefile.in all: headers $(TARGETS) diff --git a/benchmarks/common.mk b/benchmarks/common.mk index d204cbe7..21a4338a 100644 --- a/benchmarks/common.mk +++ b/benchmarks/common.mk @@ -11,7 +11,9 @@ SPIKE = $(RISCV)/bin/spike BUILD_DIR = $(REPO_BUILD)/benchmarks/$(CONFIG) -CFLAGS += -Wall -I$(BUILD_DIR)/include +CFLAGS += -Wall +CFLAGS += -I$(BUILD_DIR)/include +CFLAGS += -I$(BUILD_DIR)/include/riscvcrypto/share CFLAGS += $(CONF_CFLAGS) TEST_SRC = $(REPO_HOME)/benchmarks/share/test.c diff --git a/benchmarks/kat-gen/Makefile.in b/benchmarks/kat-gen/Makefile.in new file mode 100644 index 00000000..99b304b5 --- /dev/null +++ b/benchmarks/kat-gen/Makefile.in @@ -0,0 +1,8 @@ + +ifeq ($(ZSCRYPTO),1) + +KAT_GEN_FILES = kat-gen/kat-gen.c + +$(eval $(call add_test_elf_target,$(KAT_GEN_FILES),,kat-gen)) + +endif diff --git a/benchmarks/kat-gen/README.md b/benchmarks/kat-gen/README.md new file mode 100644 index 00000000..9ae3b0e2 --- /dev/null +++ b/benchmarks/kat-gen/README.md @@ -0,0 +1,7 @@ + +# KAT-Gen + +*Known Answer Test Generator - A tool to generate per-instruction known +answer tests for building confidence in different ISA simulators and models.* + +--- diff --git a/benchmarks/kat-gen/kat-gen.c b/benchmarks/kat-gen/kat-gen.c new file mode 100644 index 00000000..51f46802 --- /dev/null +++ b/benchmarks/kat-gen/kat-gen.c @@ -0,0 +1,218 @@ + +#include +#include + +#include "riscv-crypto-intrinsics.h" + +// How many input/output value pairs to create per instruction? +const int NUM_KATS = 10; + +// Stringification macros +#define XSTR(s) #s +#define STR(s) XSTR(s) + +//! Current XLEN-bit state of the PRNG used to create inputs. +static uint_xlen_t __rng_state; + +//! Print a 0-padded XLEN-bit value as hexadecimal. +void puthex_xlen(uint_xlen_t x) { + #if __riscv_xlen == 32 + printf("%08lX",x); + #elif __riscv_xlen == 64 + printf("%016lX",x); + #else + #error "Unsupported __riscv_xlen value. Expected 32 or 64" + #endif +} + +/* +@brief A very, very simple LFSR random number generator. +@details Tap positions taken from: +https://www.xilinx.com/support/documentation/application_notes/xapp210.pdf +*/ +uint_xlen_t sample_rng () { + #if __riscv_xlen == 32 + __rng_state = + ((__rng_state << 1 ) ) ^ + ((__rng_state >> 31) & 0x1) ^ + ((__rng_state >> 21) & 0x1) ^ + ((__rng_state >> 1) & 0x1) ^ + ((__rng_state >> 0) & 0x1) ; + #elif __riscv_xlen == 64 + __rng_state = + ((__rng_state << 1 ) ) ^ + ((__rng_state >> 63) & 0x1) ^ + ((__rng_state >> 62) & 0x1) ^ + ((__rng_state >> 60) & 0x1) ^ + ((__rng_state >> 59) & 0x1) ; + #else + #error "Unsupported __riscv_xlen value. Expected 32 or 64" + #endif + return __rng_state; +} + + +/*! +@brief Macro for creating input/output values for a 2-reg address instruction. +*/ +#define TEST_RD_RS1(INTRINSIC_FUNCTION,MNEMONIC) { \ + for(int i = 0; i < NUM_KATS; i ++) { \ + uint_xlen_t rs1= sample_rng(); \ + uint_xlen_t rd = INTRINSIC_FUNCTION (rs1); \ + printf("# " STR(MNEMONIC) " "); \ + printf(" rd=0x" ); puthex_xlen(rd ); printf("," ); \ + printf(" rs1=0x"); puthex_xlen(rs1); printf("\n"); \ + } \ +} + + +/*! +@brief Macro for creating input/output values for a 2-reg address instruction + with an immediate. +*/ +#define TEST_RD_RS1_IMM(INTRINSIC_FUNCTION,MNEMONIC, IMM) { \ + for(int i = 0; i < NUM_KATS; i ++) { \ + uint_xlen_t rs1= sample_rng(); \ + uint_xlen_t rd = INTRINSIC_FUNCTION (rs1, IMM); \ + printf("# " STR(MNEMONIC) " "); \ + printf(" rd=0x" ); puthex_xlen(rd ); printf("," ); \ + printf(" rs1=0x"); puthex_xlen(rs1); printf("," ); \ + printf(" imm=0x"); puthex_xlen(IMM); printf("\n"); \ + } \ +} + +/*! +@brief Macro for creating input/output values for a 3-reg address instruction. +*/ +#define TEST_RD_RS1_RS2(INTRINSIC_FUNCTION,MNEMONIC) { \ + for(int i = 0; i < NUM_KATS; i ++) { \ + uint_xlen_t rs1= sample_rng(); \ + uint_xlen_t rs2= sample_rng(); \ + uint_xlen_t rd = INTRINSIC_FUNCTION (rs1, rs2); \ + printf("# " STR(MNEMONIC) " "); \ + printf(" rd=0x" ); puthex_xlen(rd ); printf("," ); \ + printf(" rs1=0x"); puthex_xlen(rs1); printf("," ); \ + printf(" rs2=0x"); puthex_xlen(rs2); printf("\n"); \ + } \ +} + + +/*! +@brief Macro for creating input/output values for a 3-reg address instruction. + with a small immediate. +*/ +#define TEST_RD_RS1_RS2_IMM(INTRINSIC_FUNCTION,MNEMONIC,IMM) { \ + for(int i = 0; i < NUM_KATS; i ++) { \ + uint_xlen_t rs1= sample_rng(); \ + uint_xlen_t rs2= sample_rng(); \ + uint_xlen_t rd = INTRINSIC_FUNCTION (rs1, rs2, IMM); \ + printf("# " STR(MNEMONIC) " "); \ + printf(" rd=0x" ); puthex_xlen(rd ); printf("," ); \ + printf(" rs1=0x"); puthex_xlen(rs1); printf("," ); \ + printf(" rs2=0x"); puthex_xlen(rs2); printf("," ); \ + printf(" imm=0x"); puthex_xlen(IMM); printf("\n"); \ + } \ +} + +void generate_kats() { + + // 32/64-bit SHA256 instructions. + TEST_RD_RS1(_sha256sig0, sha256sig0) + TEST_RD_RS1(_sha256sig1, sha256sig1) + TEST_RD_RS1(_sha256sum0, sha256sum0) + TEST_RD_RS1(_sha256sum1, sha256sum1) + + // 32/64-bit SM3 instructions. + TEST_RD_RS1(_sm3p0, sm3p0) + TEST_RD_RS1(_sm3p1, sm3p1) + + // 32/64-bit SM4 instructions. + TEST_RD_RS1_RS2_IMM(_sm4ed, sm4ed, 0x0) + TEST_RD_RS1_RS2_IMM(_sm4ed, sm4ed, 0x1) + TEST_RD_RS1_RS2_IMM(_sm4ed, sm4ed, 0x2) + TEST_RD_RS1_RS2_IMM(_sm4ed, sm4ed, 0x3) + + TEST_RD_RS1_RS2_IMM(_sm4ks, sm4ks, 0x0) + TEST_RD_RS1_RS2_IMM(_sm4ks, sm4ks, 0x1) + TEST_RD_RS1_RS2_IMM(_sm4ks, sm4ks, 0x2) + TEST_RD_RS1_RS2_IMM(_sm4ks, sm4ks, 0x3) + + #if __riscv_xlen == 32 + + // 32-bit SHA-512 instructions. + TEST_RD_RS1_RS2(_sha512sig0l, sha512sig0l) + TEST_RD_RS1_RS2(_sha512sig1l, sha512sig1l) + TEST_RD_RS1_RS2(_sha512sig0h, sha512sig0h) + TEST_RD_RS1_RS2(_sha512sig1h, sha512sig1h) + TEST_RD_RS1_RS2(_sha512sum0r, sha512sum0r) + TEST_RD_RS1_RS2(_sha512sum1r, sha512sum1r) + + // 32-bit AES instructions. + TEST_RD_RS1_RS2_IMM(_aes32esi , aes32esi , 0x0) + TEST_RD_RS1_RS2_IMM(_aes32esi , aes32esi , 0x1) + TEST_RD_RS1_RS2_IMM(_aes32esi , aes32esi , 0x2) + TEST_RD_RS1_RS2_IMM(_aes32esi , aes32esi , 0x3) + + TEST_RD_RS1_RS2_IMM(_aes32esmi, aes32esmi, 0x0) + TEST_RD_RS1_RS2_IMM(_aes32esmi, aes32esmi, 0x1) + TEST_RD_RS1_RS2_IMM(_aes32esmi, aes32esmi, 0x2) + TEST_RD_RS1_RS2_IMM(_aes32esmi, aes32esmi, 0x3) + + TEST_RD_RS1_RS2_IMM(_aes32dsi , aes32dsi , 0x0) + TEST_RD_RS1_RS2_IMM(_aes32dsi , aes32dsi , 0x1) + TEST_RD_RS1_RS2_IMM(_aes32dsi , aes32dsi , 0x2) + TEST_RD_RS1_RS2_IMM(_aes32dsi , aes32dsi , 0x3) + + TEST_RD_RS1_RS2_IMM(_aes32dsmi, aes32dsmi, 0x0) + TEST_RD_RS1_RS2_IMM(_aes32dsmi, aes32dsmi, 0x1) + TEST_RD_RS1_RS2_IMM(_aes32dsmi, aes32dsmi, 0x2) + TEST_RD_RS1_RS2_IMM(_aes32dsmi, aes32dsmi, 0x3) + + #elif __riscv_xlen == 64 + + // 64-bit SHA-512 instructions. + TEST_RD_RS1(_sha512sig0, sha512sig0) + TEST_RD_RS1(_sha512sig1, sha512sig1) + TEST_RD_RS1(_sha512sum0, sha512sum0) + TEST_RD_RS1(_sha512sum1, sha512sum1) + + // 64-bit AES instructions. + TEST_RD_RS1_IMM(_aes64ks1i, aes64_ks1i, 0x0) + TEST_RD_RS1_IMM(_aes64ks1i, aes64_ks1i, 0x1) + TEST_RD_RS1_IMM(_aes64ks1i, aes64_ks1i, 0x2) + TEST_RD_RS1_IMM(_aes64ks1i, aes64_ks1i, 0x3) + TEST_RD_RS1_IMM(_aes64ks1i, aes64_ks1i, 0x4) + TEST_RD_RS1_IMM(_aes64ks1i, aes64_ks1i, 0x5) + TEST_RD_RS1_IMM(_aes64ks1i, aes64_ks1i, 0x6) + TEST_RD_RS1_IMM(_aes64ks1i, aes64_ks1i, 0x7) + TEST_RD_RS1_IMM(_aes64ks1i, aes64_ks1i, 0x8) + TEST_RD_RS1_IMM(_aes64ks1i, aes64_ks1i, 0x9) + TEST_RD_RS1_IMM(_aes64ks1i, aes64_ks1i, 0xA) + + TEST_RD_RS1_RS2(_aes64ks2 , aes64ks2 ) + TEST_RD_RS1(_aes64im , aes64im ) + TEST_RD_RS1_RS2(_aes64es , aes64es ) + TEST_RD_RS1_RS2(_aes64esm , aes64esm ) + TEST_RD_RS1_RS2(_aes64ds , aes64ds ) + TEST_RD_RS1_RS2(_aes64dsm , aes64dsm ) + #endif + +} + +int main(int argc, char ** argv) { + + printf("# RISC-V Crypto KAT GEN\n"); + printf("# XLEN = %d\n", __riscv_xlen); + + #if __riscv_xlen == 32 + __rng_state = 0x78ABCDEF; + #elif __riscv_xlen == 64 + __rng_state = 0x34ABCDEF01234567UL; + #else + #error "Unsupported __riscv_xlen value. Expected 32 or 64" + #endif + + printf("# Initial PRNG Seed: 0x"); puthex_xlen(__rng_state); printf("\n"); + + generate_kats(); +} diff --git a/benchmarks/share/riscv-crypto-intrinsics.h b/benchmarks/share/riscv-crypto-intrinsics.h index c165ccff..c1c50728 100644 --- a/benchmarks/share/riscv-crypto-intrinsics.h +++ b/benchmarks/share/riscv-crypto-intrinsics.h @@ -2,8 +2,6 @@ #include #include -#include "riscvcrypto/share/util.h" - #ifndef __RISCV_CRYPTO_INTRINSICS__ #define __RISCV_CRYPTO_INTRINSICS__ @@ -13,10 +11,12 @@ #if __riscv_xlen == 32 #define RISCV_CRYPTO_RV32 +typedef uint32_t uint_xlen_t; #endif #if __riscv_xlen == 64 #define RISCV_CRYPTO_RV64 +typedef uint64_t uint_xlen_t; #endif // @@ -83,8 +83,8 @@ static inline uint32_t _sm4ed (uint32_t rs1, uint32_t rs2, int bs) {uint32_t rd; // #if (defined(__ZSCRYPTO)) -static inline uint32_t _sm3p0 (uint32_t rs1, uint32_t rs2) {uint32_t rd; __asm__("sm3p0 %0, %1, %2" : "=r"(rd) : "r"(rs1), "r"(rs2)); return rd;} -static inline uint32_t _sm3p1 (uint32_t rs1, uint32_t rs2) {uint32_t rd; __asm__("sm3p1 %0, %1, %2" : "=r"(rd) : "r"(rs1), "r"(rs2)); return rd;} +static inline uint32_t _sm3p0 (uint32_t rs1) {uint32_t rd; __asm__("sm3p0 %0, %1" : "=r"(rd) : "r"(rs1)); return rd;} +static inline uint32_t _sm3p1 (uint32_t rs1) {uint32_t rd; __asm__("sm3p1 %0, %1" : "=r"(rd) : "r"(rs1)); return rd;} #endif //