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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,25 @@ SOURCES = slh-dsa-fast.cpp sign.cpp xn_hash.cpp \
verify.cpp stl.cpp prehash.cpp \
sha256_hash.cpp sha256_simple.cpp \
sha256.cpp sha256avx.cpp \
sha512_hash.cpp sha512.cpp mgf1_512_4x.cpp sha512avx.cpp \
sha512_hash.cpp sha512.cpp sha512avx.cpp \
sha512_simple.cpp \
shake256_hash.cpp shake256_simple.cpp \
fips202.cpp fips202x4.cpp \
keccak4x/KeccakP-1600-times4-SIMD256.o \
rdrand.cpp \
wots.cpp geo.cpp address.cpp utils.cpp
wots.cpp geo.cpp address.cpp utils.cpp \
avx512.cpp sha256avx512.cpp sha512avx512.cpp \
shake256avx512.cpp
OBJECTS = $(subst .cpp,.o,$(SOURCES))
sha256avx512.o: CFLAGS += -mavx512f
sha512avx512.o: CFLAGS += -mavx512f
shake256avx512.o: CFLAGS += -mavx512f
HEADERS = api.h internal.h sha256avx.h xn_internal.h \
fips202.h fips202x4.h
TEST_SOURCES = test_sphincs.cpp test_keygen.cpp test_sign.cpp \
test_verify.cpp test_thread.cpp test_testvector_sign.cpp \
test_testvector_keygen.cpp \
test_sha512.cpp test_context.cpp
test_sha512.cpp test_context.cpp test_avx512.cpp

TESTS = test test_slh_dsa

Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# This branch currently has AVX-512 support (except the SHA2-128F, SHA2-192F parameter sets)

## A multithreaded implementation of the SLH-DSA signature algorithm

This repository contains an alternative implementation of the SLH-DSA signature system (FIPS 205)
Expand Down
4 changes: 2 additions & 2 deletions address.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ void key::copy_subtree_addr(addr_t out, const addr_t in)
// we're talking about.
void key::set_keypair_addr(addr_t addr, uint32_t keypair)
{
((unsigned char *)addr)[offset_kp_addr2] = keypair >> 8;
((unsigned char *)addr)[offset_kp_addr1] = keypair;
addr[offset_kp_addr2] = keypair >> 8;
addr[offset_kp_addr1] = keypair;
}

//
Expand Down
71 changes: 50 additions & 21 deletions api.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,6 @@ typedef unsigned char addr_t[32];
struct digit; // Used internally, some member functions refer to it
struct signature_geometry; // Ditto

///
/// A SHAKE256 intermediate state after some prefix has been hashed
struct SHAKE256_PRECOMPUTE {
uint64_t s[25]; //<! The state of the SHAKE256 permutation
unsigned index; //<! The byte index where we absorb the next byte
unsigned nonzero; //<! Number of nonzero (64 bit) words
};

///
/// Abstract class used to generate num_track leaf nodes
class leaf_gen {
Expand All @@ -129,6 +121,11 @@ extern hash_type ph_sha256, ph_sha512;
extern hash_type ph_shake128; /// This has a 32 byte hash output
extern hash_type ph_shake256; /// This has a 64 byte hash output

/// Routine to check for the existance of AVX-512F instructions
/// The F indicates Foundational - we don't use any instructions in the
/// more advanced instruction sets
bool check_avx512(void);

///
/// This is the base class for a SLH_DSA key (either public or private)
/// It can hold a private key (which allows you to sign or verify), a public
Expand Down Expand Up @@ -166,6 +163,8 @@ class key {
const void *oid, size_t len_oid,
const void *message, size_t len_message );

bool can_avx512;

public:
enum sign_flag {
sign_success, //<! The signature was sucessfully generated
Expand Down Expand Up @@ -236,6 +235,7 @@ class key {
//<! Merkle tree
size_t wots_bytes(void) { return wots_bytes_; } //<! Length of a WOTS
//<! signature
bool avx512(void) { return can_avx512; }

const unsigned char *get_secret_seed(void); //<! Get the secret sauce we
//<! use to generate our bottom level values
Expand All @@ -254,7 +254,7 @@ class key {
/// These tell this object what geometry (e.g. the number and size of
/// FORS trees and Merkle trees) this parameter set will be using
/// It should be called only during construction
void set_geometry( size_t len_hash, size_t k, size_t t, size_t h,
virtual void set_geometry( size_t len_hash, size_t k, size_t t, size_t h,
size_t d, size_t wots_digits );
/// We're implementing a 128S parameter set
void set_128s(void) { set_geometry( 16, 14, 12, 63, 7, 35 ); }
Expand Down Expand Up @@ -410,10 +410,15 @@ class key {
leaf_gen& leaf,
addr_t* tree_addrxn);

bool do_avx512, do_avx512_verify;

/// This is the number of hashes we can compute in parallel
virtual unsigned num_track(void) = 0;
unsigned num_track_, num_track_verify_;
unsigned num_track(void) { return num_track_; }
/// This is the log2 of the number of hashes we can compute in parallel
virtual unsigned num_log_track(void) = 0;
unsigned num_log_track_, num_log_track_verify_;
unsigned num_log_track(void) { return num_log_track_; }
friend class switch_to_verify;

// Pointers into the addr structure that we use; SHA-2
// uses a different (shorter) addr structure
Expand Down Expand Up @@ -690,10 +695,43 @@ class key {
virtual ~key(void);
};

///
/// Creating this object will switch the key into verify mode (and undo it when
/// the object goes out of scope). The idea is that the verify code would
/// create a switch_to_verify object at the top (which would make things
/// appropriate for verify); when the verify is done, the destructor is called
/// which returns things to normal
///
/// This is here because there are a few parameter sets where we can't do
/// AVX-512 operations on key gen or signing, but we can on verification
class switch_to_verify {
key& k;
bool prev_do_avx512;
unsigned prev_num_track_;
unsigned prev_num_log_track_;
switch_to_verify( key& ky ) : k(ky) {
prev_do_avx512 = k.do_avx512;
k.do_avx512 = k.do_avx512_verify;
prev_num_track_ = k.num_track_;
k.num_track_ = k.num_track_verify_;
prev_num_log_track_ = k.num_log_track_;
k.num_log_track_ = k.num_log_track_verify_;
}
~switch_to_verify(void) {
k.do_avx512 = prev_do_avx512;
k.num_track_ = prev_num_track_;
k.num_log_track_ = prev_num_log_track_;
}
friend class key; // This class is the only one that can create this
};

///
/// This abstract class is for SHA2-based parameter sets
class key_sha2 : public key {
protected:
virtual void set_geometry( size_t len_hash, size_t k, size_t t, size_t h,
size_t d, size_t wots_digits );

/// This precomputes the intermediate state of the public seed (so
/// we don't have to recompute it everytime we need it).
/// This is called whenever we update the public key (which includes
Expand Down Expand Up @@ -727,9 +765,6 @@ class key_sha2 : public key {
/// The prehashed public seed
uint32_t state_seeded[8];

virtual unsigned num_track(void);
virtual unsigned num_log_track(void);

key_sha2(void);
public:
virtual void set_public_key(const unsigned char *public_key);
Expand All @@ -739,10 +774,7 @@ class key_sha2 : public key {
/// This abstract class is for SHAKE-based parameter sets
class key_shake : public key {
protected:
SHAKE256_PRECOMPUTE pre_pub_seed; //!< The prehashed public seed

virtual unsigned num_track(void);
virtual unsigned num_log_track(void);
key_shake(void);

virtual void prf_addr_xn(unsigned char **out,
const addr_t* addrxn);
Expand All @@ -764,9 +796,6 @@ class key_shake : public key {
virtual void thash_xn(unsigned char **out,
unsigned char **in,
unsigned int inblocks, addr_t* addrxn);
public:
virtual void set_public_key(const unsigned char *public_key);
virtual void set_private_key(const unsigned char *private_key);
};

// And the L3, L5 versions of the SHA2 parameter sets
Expand Down
27 changes: 27 additions & 0 deletions avx512.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include "api.h"

namespace slh_dsa {

// This returns true if we can use AVX-512F instructions on this CPU
bool check_avx512(void) {
#if 1 /* If 0, this hard disables all AVX-512 instructions */
unsigned a, b, c, d;

// Check for support of AVX-512
a = 7;
c = 0;
asm volatile("cpuid"
: "=a"(a), "=b"(b), "=c"(c), "=d"(d)
: "a"(a), "c"(c)
);
if (b & (1 << 16)) { // bit 16 of b is the avx512-f support
return true;
} else {
return false;
}
#else
return false; // We're not allowed to do AVX-512
#endif
}

} /* namespace slh_dsa */
36 changes: 1 addition & 35 deletions fips202.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ static uint64_t ROL(uint64_t a, int offset) {
const int SHAKE256_RATE = 136;

/* Keccak round constants */
static const uint64_t KeccakF_RoundConstants[NROUNDS] = {
const uint64_t KeccakF_RoundConstants[NROUNDS] = {
0x0000000000000001ULL, 0x0000000000008082ULL,
0x800000000000808aULL, 0x8000000080008000ULL,
0x000000000000808bULL, 0x0000000080000001ULL,
Expand Down Expand Up @@ -444,39 +444,5 @@ void shake256_inc_squeeze(uint8_t *output, size_t outlen, SHAKE256_CTX* ctx) {
keccak_inc_squeeze(output, outlen, ctx, SHAKE256_RATE);
}

/*
* And the precompute versions
*/
void shake256_precompute(SHAKE256_PRECOMPUTE* pre, const uint8_t *input, size_t inlen) {
SHAKE256_CTX ctx;
shake256_inc_init(&ctx);
shake256_inc_absorb(&ctx, input, inlen );

// Compute how many words need to be copied
unsigned nonzero;
if (inlen >= SHAKE256_RATE) {
// The initial absorb invoked a permute - copy everything
nonzero = 25;
} else {
// We're in the inital absorb phase - compute the number
// of words that were updated
nonzero = (inlen+7)/8;
}
memcpy( pre->s, ctx.s, nonzero * sizeof(uint64_t) );
memset( &pre->s[nonzero], 0, (25-nonzero) * sizeof(uint64_t) );
pre->index = ctx.s[25];
pre->nonzero = nonzero;
zeroize( &ctx, sizeof ctx ); // Sometimes the string we've precompted
// is secret
}

void shake256_inc_init_from_precompute(SHAKE256_CTX* ctx,
const SHAKE256_PRECOMPUTE* pre) {
unsigned nonzero = pre->nonzero;
memcpy( ctx->s, pre->s, 8*nonzero );
memset( &ctx->s[nonzero], 0, 8*(25-nonzero) );
ctx->s[25] = pre->index;
}

} /* namespace slh_dsa */

7 changes: 3 additions & 4 deletions fips202.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,14 @@ struct SHAKE256_CTX {
uint64_t s[26];
};

extern const uint64_t KeccakF_RoundConstants[24]; /* For use by the */
/* standard and AVX-512 implementations */

void shake256_inc_init(SHAKE256_CTX* ctx);
void shake256_inc_init_from_precompute(SHAKE256_CTX* ctx,
const SHAKE256_PRECOMPUTE* pre);
void shake256_inc_absorb(SHAKE256_CTX* ctx, const uint8_t *input, size_t inlen);
void shake256_inc_finalize(SHAKE256_CTX* ctx);
void shake256_inc_squeeze(uint8_t *output, size_t outlen, SHAKE256_CTX* ctx);

void shake256_precompute(SHAKE256_PRECOMPUTE* pre, const uint8_t *input, size_t inlen);

} /* namespace slh_dsa */

#endif
18 changes: 1 addition & 17 deletions fips202x4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ void shake256_4x_inc_init(SHAKE256_4X_CTX *ctx) {
ctx->index = 0;
}

const int rate = 136; // For SHAKE256
const int rate = 136; // Specific to SHAKE256 (and SHA3-256)
void shake256_4x_inc_absorb(SHAKE256_4X_CTX* ctx,
const uint8_t *input0,
const uint8_t *input1,
Expand Down Expand Up @@ -97,21 +97,5 @@ void shake256_4x_inc_squeeze(uint8_t *output0,
ctx->index = index;
}

void shake256_4x_inc_init_from_precompute(SHAKE256_4X_CTX* ctx,
const SHAKE256_PRECOMPUTE* pre) {
unsigned i;
unsigned nonzero = pre->nonzero;
for (i=0; i<nonzero; i++) {
uint64_t entry = pre->s[i];
ctx->s[i][0] = entry;
ctx->s[i][1] = entry;
ctx->s[i][2] = entry;
ctx->s[i][3] = entry;
}
memset( &ctx->s[nonzero][0], 0, 4*8*(25-nonzero) );

ctx->index = pre->index;
}

} /* namespace shl_dsa */

2 changes: 0 additions & 2 deletions fips202x4.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ typedef struct SHAKE256_4X_CTX {
} SHAKE256_4X_CTX;

void shake256_4x_inc_init(SHAKE256_4X_CTX* ctx);
void shake256_4x_inc_init_from_precompute(SHAKE256_4X_CTX* ctx,
const SHAKE256_PRECOMPUTE* pre);
void shake256_4x_inc_absorb(SHAKE256_4X_CTX* ctx,
const uint8_t *input0,
const uint8_t *input1,
Expand Down
4 changes: 2 additions & 2 deletions internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ const int max_mgf1_input = max_len_hash + sha256_addr_bytes; //<! The
//<! maximum seed size for an MGF1 input; this
//<! maximum occurs during a message hash for L5
//<! SHA256-robust parameter sets.
const unsigned max_track = 8; //<! The maximum number of hashes we can do in
//<! parallel (on a single thread) is 8
const unsigned max_track = 16; //<! The maximum number of hashes we can do in
//<! parallel (on a single thread) is 16 (SHA-256 AVX512)

const unsigned default_thread = 4; //<! If the application doesn't tell us
//<! otherwise, try to use 4 threads
Expand Down
Loading