diff --git a/Makefile b/Makefile index c98b20e..990c434 100644 --- a/Makefile +++ b/Makefile @@ -5,27 +5,26 @@ CFLAGS = -Wall -Wextra -Wpedantic -O3 -g -march=native -fomit-frame-pointer -flt %.o : %.cpp ; $(CPP) -c $(CFLAGS) $< -o $@ -SOURCES = sphincs-fast.cpp sign.cpp xn_hash.cpp \ - verify.cpp stl.cpp \ - sha256_hash.cpp sha256_simple.cpp sha256_robust.cpp \ - sha256.cpp mgf1_8x.cpp sha256avx.cpp \ +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_simple.cpp sha512_robust.cpp \ - shake256_hash.cpp shake256_simple.cpp shake256_robust.cpp \ + sha512_simple.cpp \ + shake256_hash.cpp shake256_simple.cpp \ fips202.cpp fips202x4.cpp \ keccak4x/KeccakP-1600-times4-SIMD256.o \ - haraka_hash.cpp haraka_simple.cpp haraka_robust.cpp \ - haraka.cpp \ rdrand.cpp \ wots.cpp geo.cpp address.cpp utils.cpp OBJECTS = $(subst .cpp,.o,$(SOURCES)) -HEADERS = api.h internal.h mgf1_8x.h sha256avx.h xn_internal.h \ +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.cpp \ - test_sha512.cpp + test_verify.cpp test_thread.cpp test_testvector_sign.cpp \ + test_testvector_keygen.cpp \ + test_sha512.cpp test_context.cpp -TESTS = test PQCgenKAT_sign test_sphincs +TESTS = test test_slh_dsa .PHONY: test @@ -35,15 +34,19 @@ all: test tests: $(TESTS) -sphincs-fast.a: $(OBJECTS) +slh-dsa-fast.a: $(OBJECTS) ar rcs $@ $^ test: test.cpp $(OBJECTS) $(CPP) $(CFLAGS) -o $@ $< $(OBJECTS) -lpthread -test_sphincs: $(TEST_SOURCES) $(OBJECTS) +test_slh_dsa: $(TEST_SOURCES) $(OBJECTS) $(CPP) $(CFLAGS) -o $@ $(TEST_SOURCES) $(OBJECTS) -lpthread +# The github action expects 'test_sphincs' +test_sphincs: test_slh_dsa + cp test_slh_dsa test_sphincs + PQCgenKAT_sign: PQCgenKAT_sign.o nist/nist_api.cpp rng.o $(OBJECTS) $(DET_HEADERS) $(CPP) $(CFLAGS) -o $@ $(OBJECTS) nist/nist_api.cpp rng.o $< -lcrypto -lpthread diff --git a/README.md b/README.md index d6525a8..fde5754 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -## A multithreaded implementation of the Sphincs+ signature algorithm +## A multithreaded implementation of the SLH-DSA signature algorithm -This repository contains an alternative implementation of the Sphincs+ signature system (as of round 3 of the NIST competition +This repository contains an alternative implementation of the SLH-DSA signature system (FIPS 205) The specific features that this implements (that the reference code doesn't): @@ -8,4 +8,11 @@ The specific features that this implements (that the reference code doesn't): - It can support multiple parameter sets at once -It does assume that you have the AVX2 and AES_NI instructions available, as well as the Posix multithreading API - if not, well, I'll refer you to the Sphincs+ reference code... +It does assume that you have the AVX2 instructions available, as well as the Posix multithreading API - if not, well, I'll refer you to the reference code... + +If you're looking for an implementation of the Sphincs+ round 3 code, check out the consistent-basew branch + +Interesting branches: +- fault - Attempts to protect against fault attacks (by performing the critical computations twice and comparing) +- sfluhrer-avx-512 - Uses the AVX-512 instruction set to accelerate things (if available, if not, it falls back to AVX-2) +- dwarf - Adds support for the proposed rls128cs1, rls192cs1, rls256cs1 parameter sets (both SHA2 and SHAKE) diff --git a/address.cpp b/address.cpp index f08debf..371680e 100644 --- a/address.cpp +++ b/address.cpp @@ -8,7 +8,7 @@ /// \brief This contains the accessor functions for the addr_t fields // at least, the ones that were complicated enough not to inline -namespace sphincs_plus { +namespace slh_dsa { // // Specify which Merkle tree within the level (the "tree address") we're working on @@ -54,4 +54,4 @@ void key::set_tree_index(addr_t addr, uint32_t tree_index) u32_to_bytes(&addr[offset_tree_index], tree_index ); } -} /* namespace sphincs_plus */ +} /* namespace slh_dsa */ diff --git a/api.h b/api.h index 5f77370..f73cb64 100644 --- a/api.h +++ b/api.h @@ -1,17 +1,16 @@ -#if !defined(SPHINCSPLUS_API_H_) -#define SPHINCSPLUS_API_H_ +#if !defined(SLH_DSA_API_H_) +#define SLH_DSA_API_H_ /// /// \file api.h -/// \brief This is the public interface to the fast sphincs implementation +/// \brief This is the public interface to the fast SLH-DSA implementation #include #include #include #include // For unique_ptr -#include "immintrin.h" -namespace sphincs_plus { +namespace slh_dsa { /// /// Flag that indicates whether an operation succeeded or failed @@ -75,7 +74,7 @@ class random { success_flag rdrand_fill( void *raget, size_t num_bytes ); /// -/// We do hashes in several places within the Sphincs+ structure +/// We do hashes in several places within the SLH-DSA structure /// This enum declares the reason for this specific hash enum hash_reason { ADDR_TYPE_WOTS = 0, //!< We're hashing as a part of a WOTS+ chain @@ -89,7 +88,7 @@ enum hash_reason { /// /// This is our designation of an 'address structure', called an ADRS structure -/// in the Sphincs+ documentation +/// in the SLH_DSA documentation /// It has nothing to do with IP addresses typedef unsigned char addr_t[32]; @@ -118,14 +117,27 @@ class leaf_gen { }; /// -/// This is the base class for a Sphincs+ key (either public or private) +/// If we do prehash, we need to tell SLH-DSA which hash function we used. +/// Passing in this structure is how we do it +struct hash_type { + unsigned length; // sign( + const unsigned char *message, size_t len_message, + const void *context = 0, size_t len_context = 0, + const random& rand = rdrand_fill); + + /// Generate a signature for a prehashed message using the private key + /// installed in this object. This is, we assume that the message has + /// already been hashed. On failure, this throws an exception. + /// @param[in] message The message to sign + /// @param[in] len_message The length of the message to sign + /// @param[in] context The optional signature context to sign + /// @param[in] len_context The length of the signature context + /// @param[in] hash_type The hash that was used to prehash the message /// @param[in] rand The object that returns the randomness used to generate /// this signature. If 0, this will fall back to determanistic /// signature generation. If omitted, this will fall back to @@ -488,6 +623,8 @@ class key { /// \return The unique_ptr containing the signature std::unique_ptr sign( const unsigned char *message, size_t len_message, + const hash_type& hash, + const void *context = 0, size_t len_context = 0, const random& rand = rdrand_fill); /// Verify a signature that is alleged to be for the message, using the @@ -496,11 +633,31 @@ class key { /// @param[in] len_signature The length of the signature /// @param[in] message THe message we're checking /// @param[in] len_message The length of the message + /// @param[in] context The optional signature context to sign + /// @param[in] len_context The length of the signature context /// \return Success (the signature checked out) or failure (it didn't or /// this key object doesn't have a public key to check) success_flag verify( const unsigned char *signature, size_t len_signature, - const void *message, size_t len_message); + const void *message, size_t len_message, + const void *context = 0, size_t len_context = 0); + + /// Verify a signature that is alleged to be for the prehashed message, + /// using the public key installed in this object. + /// @param[in] signature The signature we're checking + /// @param[in] len_signature The length of the signature + /// @param[in] message THe message we're checking + /// @param[in] len_message The length of the message + /// @param[in] hash_type The hash that was used to prehash the message + /// @param[in] context The optional signature context to sign + /// @param[in] len_context The length of the signature context + /// \return Success (the signature checked out) or failure (it didn't or + /// this key object doesn't have a public key to check) + success_flag verify( + const unsigned char *signature, size_t len_signature, + const void *message, size_t len_message, + const hash_type& hash, + const void *context = 0, size_t len_context = 0); /// Get the length of a signature with this parameter set /// \return The length of a signature @@ -529,12 +686,13 @@ class key { /// thread void set_num_thread(unsigned n) { num_thread = n; } + /// Destructor - just zeroizes things virtual ~key(void); }; /// -/// This abstract class is for SHA256-based parameter sets -class sha256_hash : public key { +/// This abstract class is for SHA2-based parameter sets +class key_sha2 : public key { protected: /// This precomputes the intermediate state of the public seed (so /// we don't have to recompute it everytime we need it). @@ -547,21 +705,24 @@ class sha256_hash : public key { const addr_t* addrxn); virtual void prf_msg( unsigned char *result, const unsigned char *opt, + unsigned char domain_separator_byte, + const void *context, size_t len_context, + const void *oid, size_t len_oid, const unsigned char *msg, size_t len_msg ); virtual void h_msg( unsigned char *result, size_t len_result, const unsigned char *r, - const unsigned char *msg, size_t len_msg ); + unsigned char domain_separator_byte, + const void *context, size_t len_context, + const void *oid, size_t len_oid, + const void *msg, size_t len_msg ); - // These are implementations of the prf_msg/h_msg functions - // that use SHA512 internally. It is used by the SHA256-L3, L5 - // parameter sets, in this class so that child L5 classes - // can redirect the virtual functions to these - void prf_msg_512( unsigned char *result, - const unsigned char *opt, - const unsigned char *msg, size_t len_msg ); - void h_msg_512( unsigned char *result, size_t len_result, - const unsigned char *r, - const unsigned char *msg, size_t len_msg ); + // The implementations of the thash function + virtual void thash(unsigned char *out, + const unsigned char *in, + unsigned int inblocks, addr_t addr); + virtual void thash_xn(unsigned char **out, + unsigned char **in, + unsigned int inblocks, addr_t* addrxn); /// The prehashed public seed uint32_t state_seeded[8]; @@ -569,14 +730,14 @@ class sha256_hash : public key { virtual unsigned num_track(void); virtual unsigned num_log_track(void); - sha256_hash(void); + key_sha2(void); public: virtual void set_public_key(const unsigned char *public_key); virtual void set_private_key(const unsigned char *private_key); }; -/// This abstract class is for SHAKE256-based parameter sets -class shake256_hash : 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 @@ -587,92 +748,34 @@ class shake256_hash : public key { const addr_t* addrxn); virtual void prf_msg( unsigned char *result, const unsigned char *opt, + unsigned char domain_separator_byte, + const void *context, size_t len_context, + const void *oid, size_t len_oid, const unsigned char *msg, size_t len_msg ); virtual void h_msg( unsigned char *result, size_t len_result, const unsigned char *r, - const unsigned char *msg, size_t len_msg ); -public: - virtual void set_public_key(const unsigned char *public_key); - virtual void set_private_key(const unsigned char *private_key); -}; - -/// This abstract class is for Haraka-based parameter sets -class haraka_hash : public key { -protected: - __m128i pub_seed_expanded[40]; //s[25] = pre->index; } -} /* namespace sphincs_plus */ +} /* namespace slh_dsa */ diff --git a/fips202.h b/fips202.h index 03bcd88..6b04d6b 100644 --- a/fips202.h +++ b/fips202.h @@ -5,7 +5,7 @@ #include #include "api.h" -namespace sphincs_plus { +namespace slh_dsa { struct SHAKE256_CTX { uint64_t s[26]; @@ -20,6 +20,6 @@ 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 sphincs_plus */ +} /* namespace slh_dsa */ #endif diff --git a/fips202x4.cpp b/fips202x4.cpp index cdff203..7bbda28 100644 --- a/fips202x4.cpp +++ b/fips202x4.cpp @@ -9,7 +9,7 @@ */ #include "keccak4x/KeccakP-1600-times4-SnP.h" -namespace sphincs_plus { +namespace slh_dsa { void shake256_4x_inc_init(SHAKE256_4X_CTX *ctx) { memset( ctx->s, 0, sizeof ctx->s ); @@ -113,5 +113,5 @@ void shake256_4x_inc_init_from_precompute(SHAKE256_4X_CTX* ctx, ctx->index = pre->index; } -} /* namespace sphincs_plus */ +} /* namespace shl_dsa */ diff --git a/fips202x4.h b/fips202x4.h index 361af30..025fe58 100644 --- a/fips202x4.h +++ b/fips202x4.h @@ -14,7 +14,7 @@ #include #include "api.h" -namespace sphincs_plus { +namespace slh_dsa { typedef struct SHAKE256_4X_CTX { union { @@ -40,6 +40,6 @@ void shake256_4x_inc_squeeze(uint8_t *output0, uint8_t *output3, size_t outlen, SHAKE256_4X_CTX* ctx); -} /* namespace sphincs_plus */ +} /* namespace slh_dsa */ #endif /* FIPS202X4_H_ */ diff --git a/geo.cpp b/geo.cpp index 7d054ea..f7e9bc4 100644 --- a/geo.cpp +++ b/geo.cpp @@ -4,10 +4,10 @@ #include "internal.h" /// \file geo.cpp -/// \brief This contains hash the message into the fields used by Sphincs+, +/// \brief This contains hash the message into the fields used by SLH-DSA, /// as well as to initialize the fixed fields in the geo structure -namespace sphincs_plus { +namespace slh_dsa { /// This lays out where things are within a signature /// That is, the offsets where the various FORS, WOTS+ and Merkle tree @@ -53,23 +53,33 @@ class bit_extract { unsigned r = 0; unsigned count_bits = 0; while (bits >= bits_in_byte) { - r |= *p++ << count_bits; + // The region we're extracting extends to the end of the byte + // we're scanning; extract what's remaining, and add it to + // the result (after shifting it into the correct position) + r |= *p++ << (bits - bits_in_byte); count_bits += bits_in_byte; bits -= bits_in_byte; bits_in_byte = 8; } if (bits > 0) { - unsigned mask = (1 << bits) - 1; - r += (*p & mask) << count_bits; - *p >>= bits; + // The region we're extracting ends in the middle of this byte + // Set the mask to cover that reguin; add those to the result + // (after shifting it to the correct position) + unsigned mask = ((1 << bits) - 1) << (bits_in_byte - bits); + r += (*p & mask) >> (bits_in_byte - bits); + bits_in_byte -= bits; + + // And remove those bits from teh byte (so it doesn't interfere + // with th enext field we extract) + *p &= ~mask; } return r; } /// Extract the next n bits from the buffer as an integer. Note that /// this actually reads the next ceil(bits/8) bytes, and ignores the /// msbits if bits isn't a multiple of 8. This is behavior distinct - /// from the extra_bits function - for whatever reason, Sphincs+ uses + /// from the extra_bits function - for whatever reason, SLH-DSA uses /// this behavior to read the Merkle tree/Hypertree locations from /// the bitstream /// @param[in] bits Number of bits to extract @@ -89,8 +99,11 @@ class bit_extract { /// /// This converts a message (and randomness) into the FORS/Merkle indices void key::hash_message(struct signature_geometry& geo, - const unsigned char *r, - const unsigned char *message, size_t len_message ) { + const unsigned char *r, + unsigned char domain_separator_byte, + const void *context, size_t len_context, + const void *oid, size_t len_oid, + const void *message, size_t len_message ) { unsigned char msg_hash[ max_len_h_msg ]; @@ -100,14 +113,13 @@ void key::hash_message(struct signature_geometry& geo, // Merkle tree len_h += (merkle_height() + 7)/8; // For the leaf of the bottom Merkle - h_msg( msg_hash, len_h, r, message, len_message ); + h_msg( msg_hash, len_h, r, domain_separator_byte, context, + len_context, oid, len_oid, message, len_message ); /* Now, parse that output into the individual values */ bit_extract bit( msg_hash, len_h ); /* The first k*a bits are the digits of the FORS trees */ - /* Note that the byte ordering is reversed; that's what the Sphincs+ */ - /* reference code does */ for (unsigned i=0; i -#include -#include -#include - -#include "api.h" -#include "immintrin.h" -#include "haraka.h" - -namespace sphincs_plus { - -const size_t HARAKAS_RATE = 32; - -#define LOAD(src) _mm_load_si128((u128 *)(src)) -#define STORE(dest,src) _mm_storeu_si128((u128 *)(dest),src) - -#define XOR128(a, b) _mm_xor_si128(a, b) - -#define AES2(s0, s1, rci) \ - s0 = _mm_aesenc_si128(s0, *(rci)); \ - s1 = _mm_aesenc_si128(s1, *(rci + 1)); \ - s0 = _mm_aesenc_si128(s0, *(rci + 2)); \ - s1 = _mm_aesenc_si128(s1, *(rci + 3)); - -#define AES2_4x(s0, s1, s2, s3, rci) \ - AES2(s0[0], s0[1], rci); \ - AES2(s1[0], s1[1], rci); \ - AES2(s2[0], s2[1], rci); \ - AES2(s3[0], s3[1], rci); - -#define AES4(s0, s1, s2, s3, rci) \ - s0 = _mm_aesenc_si128(s0, *(rci)); \ - s1 = _mm_aesenc_si128(s1, *(rci + 1)); \ - s2 = _mm_aesenc_si128(s2, *(rci + 2)); \ - s3 = _mm_aesenc_si128(s3, *(rci + 3)); \ - s0 = _mm_aesenc_si128(s0, *(rci + 4)); \ - s1 = _mm_aesenc_si128(s1, *(rci + 5)); \ - s2 = _mm_aesenc_si128(s2, *(rci + 6)); \ - s3 = _mm_aesenc_si128(s3, *(rci + 7)); - -#define AES4_4x(s0, s1, s2, s3, rci) \ - AES4(s0[0], s0[1], s0[2], s0[3], rci); \ - AES4(s1[0], s1[1], s1[2], s1[3], rci); \ - AES4(s2[0], s2[1], s2[2], s2[3], rci); \ - AES4(s3[0], s3[1], s3[2], s3[3], rci); - -#define MIX2(s0, s1) \ - tmp = _mm_unpacklo_epi32(s0, s1); \ - s1 = _mm_unpackhi_epi32(s0, s1); \ - s0 = tmp; - -#define MIX4(s0, s1, s2, s3) \ - tmp = _mm_unpacklo_epi32(s0, s1); \ - s0 = _mm_unpackhi_epi32(s0, s1); \ - s1 = _mm_unpacklo_epi32(s2, s3); \ - s2 = _mm_unpackhi_epi32(s2, s3); \ - s3 = _mm_unpacklo_epi32(s0, s2); \ - s0 = _mm_unpackhi_epi32(s0, s2); \ - s2 = _mm_unpackhi_epi32(s1, tmp); \ - s1 = _mm_unpacklo_epi32(s1, tmp); - -#define TRUNCSTORE(out, s0, s1, s2, s3) \ - _mm_storeu_si128(out, \ - (__m128i)_mm_shuffle_pd((__m128d)(s0), (__m128d)(s1), 3)); \ - _mm_storeu_si128((out + 1), \ - (__m128i)_mm_shuffle_pd((__m128d)(s2), (__m128d)(s3), 0)); - -// This transforms the data in place -void haraka512::permute( u128* s ) { - u128 tmp; - - AES4(s[0], s[1], s[2], s[3], rc); - MIX4(s[0], s[1], s[2], s[3]); - - AES4(s[0], s[1], s[2], s[3], rc + 8); - MIX4(s[0], s[1], s[2], s[3]); - - AES4(s[0], s[1], s[2], s[3], rc + 16); - MIX4(s[0], s[1], s[2], s[3]); - - AES4(s[0], s[1], s[2], s[3], rc + 24); - MIX4(s[0], s[1], s[2], s[3]); - - AES4(s[0], s[1], s[2], s[3], rc + 32); - MIX4(s[0], s[1], s[2], s[3]); -} - -void harakaS::absorb( const unsigned char* msg, unsigned len_msg ) { - while (len_msg > 0) { - unsigned bytes = len_msg; - if (bytes + index > HARAKAS_RATE) { - bytes = HARAKAS_RATE - index; - } - for (unsigned i = 0; i 0) { - if (index == HARAKAS_RATE) { - perm.permute( long_buffer ); - index = 0; - } - - unsigned bytes = len_output; - if (bytes + index > HARAKAS_RATE) { - bytes = HARAKAS_RATE - index; - } - memcpy( output, buffer+index, bytes); - len_output -= bytes; - output += bytes; - index += bytes; - } -} - -void haraka512_4x::permute( u128 *s0, u128 *s1, u128 *s2, u128 *s3, - const u128 *in_0, const u128 *in_1, - const u128 *in_2, const u128 *in_3) { - u128 tmp; - - memcpy( s0, in_0, 4 * sizeof(u128) ); - memcpy( s1, in_1, 4 * sizeof(u128) ); - memcpy( s2, in_2, 4 * sizeof(u128) ); - memcpy( s3, in_3, 4 * sizeof(u128) ); - - AES4_4x(s0, s1, s2, s3, rc); - MIX4(s0[0], s0[1], s0[2], s0[3]); - MIX4(s1[0], s1[1], s1[2], s1[3]); - MIX4(s2[0], s2[1], s2[2], s2[3]); - MIX4(s3[0], s3[1], s3[2], s3[3]); - - AES4_4x(s0, s1, s2, s3, rc + 8); - MIX4(s0[0], s0[1], s0[2], s0[3]); - MIX4(s1[0], s1[1], s1[2], s1[3]); - MIX4(s2[0], s2[1], s2[2], s2[3]); - MIX4(s3[0], s3[1], s3[2], s3[3]); - - AES4_4x(s0, s1, s2, s3, rc + 16); - MIX4(s0[0], s0[1], s0[2], s0[3]); - MIX4(s1[0], s1[1], s1[2], s1[3]); - MIX4(s2[0], s2[1], s2[2], s2[3]); - MIX4(s3[0], s3[1], s3[2], s3[3]); - - AES4_4x(s0, s1, s2, s3, rc + 24); - MIX4(s0[0], s0[1], s0[2], s0[3]); - MIX4(s1[0], s1[1], s1[2], s1[3]); - MIX4(s2[0], s2[1], s2[2], s2[3]); - MIX4(s3[0], s3[1], s3[2], s3[3]); - - AES4_4x(s0, s1, s2, s3, rc + 32); - MIX4(s0[0], s0[1], s0[2], s0[3]); - MIX4(s1[0], s1[1], s1[2], s1[3]); - MIX4(s2[0], s2[1], s2[2], s2[3]); - MIX4(s3[0], s3[1], s3[2], s3[3]); -} - -void haraka512_4x::transform( u128 *out0, u128 *out1, u128 *out2, u128 *out3, - const u128 *in_0, const u128 *in_1, - const u128 *in_2, const u128 *in_3) { - u128 s[4][4]; - - permute( s[0], s[1], s[2], s[3], - in_0, in_1, in_2, in_3 ); - - TRUNCSTORE(out0, s[0][0]^in_0[0], - s[0][1]^in_0[1], - s[0][2]^in_0[2], - s[0][3]^in_0[3]); - TRUNCSTORE(out1, s[1][0]^in_1[0], - s[1][1]^in_1[1], - s[1][2]^in_1[2], - s[1][3]^in_1[3]); - TRUNCSTORE(out2, s[2][0]^in_2[0], - s[2][1]^in_2[1], - s[2][2]^in_2[2], - s[2][3]^in_2[3]); - TRUNCSTORE(out3, s[3][0]^in_3[0], - s[3][1]^in_3[1], - s[3][2]^in_3[2], - s[3][3]^in_3[3]); -} - -void harakaS_4x::absorb( unsigned char** msg, unsigned len_msg ) { - unsigned msg_processed = 0; - while (len_msg > 0) { - unsigned bytes = len_msg; - if (bytes + index > HARAKAS_RATE) { - bytes = HARAKAS_RATE - index; - } - for (int j=0; j<4; j++) { - unsigned char* m = msg[j] + msg_processed; - for (unsigned i = 0; i 0) { - if (index == HARAKAS_RATE) { - perm.permute( u128_buffer[0], u128_buffer[1], - u128_buffer[2], u128_buffer[3], - u128_buffer[0], u128_buffer[1], - u128_buffer[2], u128_buffer[3] ); - index = 0; - } - - unsigned bytes = len_output; - if (bytes + index > HARAKAS_RATE) { - bytes = HARAKAS_RATE - index; - } - for (int j=0; j<4; j++) { - memcpy( output[j] + output_so_far, &buffer[j][index], bytes); - } - len_output -= bytes; - output_so_far += bytes; - index += bytes; - } -} - -void haraka256_4x::transform( u128* s0, u128* s1, u128* s2, u128* s3, - const u128 *in0, const u128 *in1, - const u128 *in2, const u128 *in3 ) { - u128 tmp; - - memcpy( s0, in0, 2*sizeof(u128) ); - memcpy( s1, in1, 2*sizeof(u128) ); - memcpy( s2, in2, 2*sizeof(u128) ); - memcpy( s3, in3, 2*sizeof(u128) ); - - // Round 1 - AES2_4x(s0, s1, s2, s3, rc); - - MIX2(s0[0], s0[1]); - MIX2(s1[0], s1[1]); - MIX2(s2[0], s2[1]); - MIX2(s3[0], s3[1]); - - // Round 2 - AES2_4x(s0, s1, s2, s3, rc + 4); - - MIX2(s0[0], s0[1]); - MIX2(s1[0], s1[1]); - MIX2(s2[0], s2[1]); - MIX2(s3[0], s3[1]); - - // Round 3 - AES2_4x(s0, s1, s2, s3, rc + 8); - - MIX2(s0[0], s0[1]); - MIX2(s1[0], s1[1]); - MIX2(s2[0], s2[1]); - MIX2(s3[0], s3[1]); - - // Round 4 - AES2_4x(s0, s1, s2, s3, rc + 12); - - MIX2(s0[0], s0[1]); - MIX2(s1[0], s1[1]); - MIX2(s2[0], s2[1]); - MIX2(s3[0], s3[1]); - - // Round 5 - AES2_4x(s0, s1, s2, s3, rc + 16); - - MIX2(s0[0], s0[1]); - MIX2(s1[0], s1[1]); - MIX2(s2[0], s2[1]); - MIX2(s3[0], s3[1]); - - // Feed Forward - s0[0] ^= in0[0]; - s0[1] ^= in0[1]; - s1[0] ^= in1[0]; - s1[1] ^= in1[1]; - s2[0] ^= in2[0]; - s2[1] ^= in2[1]; - s3[0] ^= in3[0]; - s3[1] ^= in3[1]; -} - -} /* namespace sphincs_plus */ diff --git a/haraka.h b/haraka.h deleted file mode 100644 index 016894d..0000000 --- a/haraka.h +++ /dev/null @@ -1,126 +0,0 @@ -#if !defined( HARAKA_H_ ) -#define HARAKA_H_ - -#include "immintrin.h" - -/// \file haraka.h -/// \brief This contains the declaration of the low level Haraka classes - -namespace sphincs_plus { - -typedef uint64_t u64; -typedef __m128i u128; - -/// This is a class that computes the Haraka512 permutation -class haraka512 { - const u128* rc; -public: - /// Create a haraka512 object based on a specific seed - haraka512( const u128* this_seed ) : rc(this_seed) { ; } - - /// Permute the 64 byte object based on the seed - /// @param data Data to permute - void permute( u128* data ); -}; - -/// This is a class that implementates the Haraka keyed XOF -class harakaS { - /// This is the current state of the XOF permutation - union { - unsigned char buffer[64]; - u128 long_buffer[4]; - }; - unsigned index; // -#include "api.h" -#include "internal.h" -#include "haraka.h" -#include "immintrin.h" - -namespace sphincs_plus { - -static void set_default_constants( u128* rc ) { - rc[0] = _mm_set_epi32(0x0684704c,0xe620c00a,0xb2c5fef0,0x75817b9d); - rc[1] = _mm_set_epi32(0x8b66b4e1,0x88f3a06b,0x640f6ba4,0x2f08f717); - rc[2] = _mm_set_epi32(0x3402de2d,0x53f28498,0xcf029d60,0x9f029114); - rc[3] = _mm_set_epi32(0x0ed6eae6,0x2e7b4f08,0xbbf3bcaf,0xfd5b4f79); - rc[4] = _mm_set_epi32(0xcbcfb0cb,0x4872448b,0x79eecd1c,0xbe397044); - rc[5] = _mm_set_epi32(0x7eeacdee,0x6e9032b7,0x8d5335ed,0x2b8a057b); - rc[6] = _mm_set_epi32(0x67c28f43,0x5e2e7cd0,0xe2412761,0xda4fef1b); - rc[7] = _mm_set_epi32(0x2924d9b0,0xafcacc07,0x675ffde2,0x1fc70b3b); - rc[8] = _mm_set_epi32(0xab4d63f1,0xe6867fe9,0xecdb8fca,0xb9d465ee); - rc[9] = _mm_set_epi32(0x1c30bf84,0xd4b7cd64,0x5b2a404f,0xad037e33); - rc[10] = _mm_set_epi32(0xb2cc0bb9,0x941723bf,0x69028b2e,0x8df69800); - rc[11] = _mm_set_epi32(0xfa0478a6,0xde6f5572,0x4aaa9ec8,0x5c9d2d8a); - rc[12] = _mm_set_epi32(0xdfb49f2b,0x6b772a12,0x0efa4f2e,0x29129fd4); - rc[13] = _mm_set_epi32(0x1ea10344,0xf449a236,0x32d611ae,0xbb6a12ee); - rc[14] = _mm_set_epi32(0xaf044988,0x4b050084,0x5f9600c9,0x9ca8eca6); - rc[15] = _mm_set_epi32(0x21025ed8,0x9d199c4f,0x78a2c7e3,0x27e593ec); - rc[16] = _mm_set_epi32(0xbf3aaaf8,0xa759c9b7,0xb9282ecd,0x82d40173); - rc[17] = _mm_set_epi32(0x6260700d,0x6186b017,0x37f2efd9,0x10307d6b); - rc[18] = _mm_set_epi32(0x5aca45c2,0x21300443,0x81c29153,0xf6fc9ac6); - rc[19] = _mm_set_epi32(0x9223973c,0x226b68bb,0x2caf92e8,0x36d1943a); - rc[20] = _mm_set_epi32(0xd3bf9238,0x225886eb,0x6cbab958,0xe51071b4); - rc[21] = _mm_set_epi32(0xdb863ce5,0xaef0c677,0x933dfddd,0x24e1128d); - rc[22] = _mm_set_epi32(0xbb606268,0xffeba09c,0x83e48de3,0xcb2212b1); - rc[23] = _mm_set_epi32(0x734bd3dc,0xe2e4d19c,0x2db91a4e,0xc72bf77d); - rc[24] = _mm_set_epi32(0x43bb47c3,0x61301b43,0x4b1415c4,0x2cb3924e); - rc[25] = _mm_set_epi32(0xdba775a8,0xe707eff6,0x03b231dd,0x16eb6899); - rc[26] = _mm_set_epi32(0x6df3614b,0x3c755977,0x8e5e2302,0x7eca472c); - rc[27] = _mm_set_epi32(0xcda75a17,0xd6de7d77,0x6d1be5b9,0xb88617f9); - rc[28] = _mm_set_epi32(0xec6b43f0,0x6ba8e9aa,0x9d6c069d,0xa946ee5d); - rc[29] = _mm_set_epi32(0xcb1e6950,0xf957332b,0xa2531159,0x3bf327c1); - rc[30] = _mm_set_epi32(0x2cee0c75,0x00da619c,0xe4ed0353,0x600ed0d9); - rc[31] = _mm_set_epi32(0xf0b1a5a1,0x96e90cab,0x80bbbabc,0x63a4a350); - rc[32] = _mm_set_epi32(0xae3db102,0x5e962988,0xab0dde30,0x938dca39); - rc[33] = _mm_set_epi32(0x17bb8f38,0xd554a40b,0x8814f3a8,0x2e75b442); - rc[34] = _mm_set_epi32(0x34bb8a5b,0x5f427fd7,0xaeb6b779,0x360a16f6); - rc[35] = _mm_set_epi32(0x26f65241,0xcbe55438,0x43ce5918,0xffbaafde); - rc[36] = _mm_set_epi32(0x4ce99a54,0xb9f3026a,0xa2ca9cf7,0x839ec978); - rc[37] = _mm_set_epi32(0xae51a51a,0x1bdff7be,0x40c06e28,0x22901235); - rc[38] = _mm_set_epi32(0xa0c1613c,0xba7ed22b,0xc173bc0f,0x48a659cf); - rc[39] = _mm_set_epi32(0x756acc03,0x02288288,0x4ad6bdfd,0xe9c59da1); -} - -static void expand_seed( u128 *expanded, const unsigned char *pub_seed, size_t n ) { - u128 default_rc[40]; - set_default_constants( default_rc ); - - harakaS expander( default_rc ); - expander.absorb( pub_seed, n ); - expander.finalize(); - expander.squeeze( (unsigned char*)expanded, 40*16 ); -} - -void haraka_hash::set_public_key(const unsigned char *public_key) { - key::set_public_key(public_key); - expand_seed( pub_seed_expanded, get_public_seed(), len_hash() ); -} - -void haraka_hash::set_private_key(const unsigned char *private_key) { - key::set_private_key(private_key); - expand_seed( pub_seed_expanded, get_public_seed(), len_hash() ); -} - -/* - * 4-way parallel version of prf_addr; takes 4x as much input and output - * This is SHAKE-256 specific - */ -void haraka_hash::prf_addr_xn(unsigned char **out, - const addr_t* addrx4) -{ - unsigned n = len_hash(); - union { - unsigned char input_buffer[4][ addr_bytes + max_len_hash ]; - u128 input_u128[4][4]; - }; - const unsigned char* secret_seed = get_secret_seed(); - for (int i=0; i<4; i++) { - memcpy( &input_buffer[i][0], addrx4+i, addr_bytes ); - memcpy( &input_buffer[i][32], secret_seed, n ); - memset( &input_buffer[i][32+n], 0, 32-n ); - } - - u128 output_buffer[4][2]; - - haraka512_4x prf( pub_seed_expanded ); - prf.transform( output_buffer[0], output_buffer[1], - output_buffer[2], output_buffer[3], - input_u128[0], input_u128[1], - input_u128[2], input_u128[3] ); - - for (int i=0; i<4; i++) { - memcpy(out[i], output_buffer[i], n); - } -} - -// prf_msg is defined as HarakaS_pk.seed( prf || optrand || msg ) -void haraka_hash::prf_msg( unsigned char *result, - const unsigned char *opt_rand, - const unsigned char *msg, size_t len_msg ) { - harakaS expander( pub_seed_expanded ); - unsigned n = len_hash(); - expander.absorb( get_prf(), n ); - expander.absorb( opt_rand, n ); - expander.absorb( msg, len_msg ); - expander.finalize(); - expander.squeeze( result, n ); -} - -// Here, len_result is not the size of the buffer (which it is in most -// similar contexts); instead, it is the number of output bytes desired -void haraka_hash::h_msg( unsigned char *result, size_t len_result, - const unsigned char *r, - const unsigned char *msg, size_t len_msg ) { - harakaS expander( pub_seed_expanded ); - unsigned n = len_hash(); - expander.absorb( r, n ); - expander.absorb( get_root(), n ); - expander.absorb( msg, len_msg ); - expander.finalize(); - expander.squeeze( result, len_result ); -} - -unsigned haraka_hash::num_track(void) { - return 4; -} -unsigned haraka_hash::num_log_track(void) { - return 2; -} - -} /* namespace sphincs_plus */ diff --git a/haraka_robust.cpp b/haraka_robust.cpp deleted file mode 100644 index eff740b..0000000 --- a/haraka_robust.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* - * This file has support for the low level Harak-robust routines - */ -#include -#include "api.h" -#include "internal.h" -#include "haraka.h" - -namespace sphincs_plus { - -static void memxor( unsigned char *dest, const unsigned char *src, unsigned count ) { - while (count--) { - *dest++ ^= *src++; - } -} - -/** - * The robust version of thash - */ -void key_haraka_robust::thash( unsigned char *out, - const unsigned char *in, - unsigned int inblocks, addr_t addr) { - unsigned n = len_hash(); - - harakaS mask( pub_seed_expanded ); - mask.absorb( addr, addr_bytes ); - mask.finalize(); - - harakaS expander( pub_seed_expanded ); - expander.absorb( addr, addr_bytes ); - for (unsigned i=0; i -#include "api.h" -#include "internal.h" -#include "haraka.h" - -namespace sphincs_plus { - -/** - * The simple version of thash - */ -void key_haraka_simple::thash( unsigned char *out, - const unsigned char *in, - unsigned int inblocks, addr_t addr) { - unsigned n = len_hash(); - - harakaS expander( pub_seed_expanded ); - expander.absorb( addr, addr_bytes ); - expander.absorb( in, inblocks * n ); - expander.finalize(); - expander.squeeze( out, n ); -} - -/** - * 4-way parallel version of thash; takes 4x as much input and output - */ -void key_haraka_simple::thash_xn(unsigned char **out, - unsigned char **in, - unsigned int inblocks, - addr_t* addrx4) { - unsigned n = len_hash(); - unsigned char *addr_vector[4]; - addr_vector[0] = addrx4[0]; - addr_vector[1] = addrx4[1]; - addr_vector[2] = addrx4[2]; - addr_vector[3] = addrx4[3]; - - harakaS_4x expander( pub_seed_expanded ); - expander.absorb( addr_vector, addr_bytes ); - expander.absorb( in, n * inblocks ); - expander.finalize(); - expander.squeeze( out, n ); -} - -void key_haraka_simple::f_xn(unsigned char **out, unsigned char **in, - addr_t* addrx4) { - unsigned n = len_hash(); - union { - unsigned char input_buffer[4][ addr_bytes + max_len_hash ]; - u128 input_u128[4][4]; - }; - for (int i=0; i<4; i++) { - memcpy( &input_buffer[i][0], addrx4+i, addr_bytes ); - memcpy( &input_buffer[i][32], in[i], n ); - memset( &input_buffer[i][32+n], 0, 32-n ); - } - - u128 output_buffer[4][2]; - - haraka512_4x prf( pub_seed_expanded ); - prf.transform( output_buffer[0], output_buffer[1], - output_buffer[2], output_buffer[3], - input_u128[0], input_u128[1], - input_u128[2], input_u128[3] ); - - for (int i=0; i<4; i++) { - memcpy(out[i], output_buffer[i], n); - } -} - -} /* sphincs_plus */ diff --git a/internal.h b/internal.h index cfb920e..68b9aff 100644 --- a/internal.h +++ b/internal.h @@ -2,12 +2,12 @@ #define INTERNAL_H_ /// \file internal.h -/// \brief Definitions used internally for the fast Sphincs+ implementation +/// \brief Definitions used internally for the fast SLH-DSA implementation /// That is, the ones that don't need to be mentioned within api.h // #include -namespace sphincs_plus { +namespace slh_dsa { // Various constants that are used internally (but needn't be published in api.h) const int wots_w = 16; // class mgf1 { } }; -} /* namespace sphincs_plus */ +} /* namespace slh_dsa */ #endif /* MGF1_H_ */ diff --git a/mgf1_512_4x.cpp b/mgf1_512_4x.cpp index 1f888d9..ff35627 100644 --- a/mgf1_512_4x.cpp +++ b/mgf1_512_4x.cpp @@ -10,7 +10,7 @@ #include "mgf1_512_4x.h" #include "sha512avx.h" -namespace sphincs_plus { +namespace slh_dsa { mgf1_sha512_4x::mgf1_sha512_4x( unsigned char **seed_vector, unsigned seed_len ) { for (int i=0; i<4; i++) { @@ -64,5 +64,5 @@ void mgf1_sha512_4x::output( unsigned char **buffer, unsigned len_output ) { } } -} /* namespace sphincs_plus */ +} /* namespace slh_dsa */ diff --git a/mgf1_512_4x.h b/mgf1_512_4x.h index 194c84f..e5adc46 100644 --- a/mgf1_512_4x.h +++ b/mgf1_512_4x.h @@ -4,7 +4,7 @@ #include "internal.h" #include "immintrin.h" -namespace sphincs_plus { +namespace slh_dsa { class mgf1_sha512_4x { unsigned char state[4][max_mgf1_input+4]; @@ -20,6 +20,6 @@ class mgf1_sha512_4x { void output( unsigned char **buffer, unsigned len_ouptut ); }; -} /* namespace sphincs_plus */ +} /* namespace slh_dsa */ #endif /* MGF1_512_4X_H_ */ diff --git a/mgf1_8x.cpp b/mgf1_8x.cpp deleted file mode 100644 index 1e142f6..0000000 --- a/mgf1_8x.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * The 8 track version of MGF1; it generates 8 outputs in parallel, using the - * AVX2 8-way parallel hash implementation - * - * This is in its own file because it is used only by the SHA-256 robust - * parameter sets - */ - -#include -#include "mgf1_8x.h" -#include "sha256avx.h" - -namespace sphincs_plus { - -mgf1_8x::mgf1_8x( unsigned char **seed_vector, unsigned seed_len ) { - for (int i=0; i<8; i++) { - memcpy( state[i], seed_vector[i], seed_len ); - } - state_len = seed_len; - next_index = 0; - output_index = sha256_output_size; -} - -void mgf1_8x::output( unsigned char **buffer, unsigned len_output ) { - unsigned inserted = 0; // Number of bytes we have already generated - for (;;) { - unsigned left_in_buffer = sha256_output_size - output_index; - if (left_in_buffer > len_output) { - left_in_buffer = len_output; - } - if (left_in_buffer > 0) { - for (int i=0; i<8; i++) { - memcpy( buffer[i] + inserted, - &char_output_buffer[i][output_index], - left_in_buffer ); - } - output_index += left_in_buffer; - inserted += left_in_buffer; - len_output -= left_in_buffer; - } - if (len_output == 0) break; - - // We need to generate some fresh output - unsigned char index[4]; - ull_to_bytes( index, 4, next_index ); - for (int i=0; i<8; i++) { - memcpy( &state[i][ state_len ], index, 4 ); - } - next_index += 1; - sha256ctx8x ctx; - sha256_init8x(&ctx); - sha256_update8x(&ctx, - state[0], - state[1], - state[2], - state[3], - state[4], - state[5], - state[6], - state[7], - state_len+4); - sha256_final8x(&ctx, - output_buffer[0], - output_buffer[1], - output_buffer[2], - output_buffer[3], - output_buffer[4], - output_buffer[5], - output_buffer[6], - output_buffer[7]); - output_index = 0; - } -} - -} /* namespace sphincs_plus */ - diff --git a/mgf1_8x.h b/mgf1_8x.h deleted file mode 100644 index d018f23..0000000 --- a/mgf1_8x.h +++ /dev/null @@ -1,25 +0,0 @@ -#if !defined(MGF1_8X_H_) -#define MGF1_8X_H_ - -#include "internal.h" -#include "immintrin.h" - -namespace sphincs_plus { - -class mgf1_8x { - unsigned char state[8][max_mgf1_input+4]; - unsigned int state_len; - unsigned int next_index; - unsigned char output_index; - union { - __m256i output_buffer[8][ sha256_output_size / sizeof(__m256i) ]; - unsigned char char_output_buffer[8][ sha256_output_size ]; - }; -public: - mgf1_8x( unsigned char **seed, unsigned seed_len ); - void output( unsigned char **buffer, unsigned len_ouptut ); -}; - -} /* namespace sphincs_plus */ - -#endif /* MGF1_8X_H_ */ diff --git a/prehash.cpp b/prehash.cpp new file mode 100644 index 0000000..a0db460 --- /dev/null +++ b/prehash.cpp @@ -0,0 +1,90 @@ +/// +/// \file prehash.cpp +/// \brief This is the module that supports the prehash version of SLH-DSA +/// +/// It's in a separate module because it is rarely used +/// +#include +#include +#include "api.h" +#include "internal.h" + +namespace slh_dsa { + +// +// The various prehash OIDs +// +// SHA256 +hash_type ph_sha256 = { + 32, 11, + "\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01" +}; + +// SHA512 +hash_type ph_sha512 = { + 64, 11, + "\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03" +}; + +// SHAKE-128 (32 byte output) +hash_type ph_shake128 = { + 32, 11, + "\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x0B" +}; + +// SHAKE-256 (64 byte otuput) +hash_type ph_shake256 = { + 64, 11, + "\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x0C" +}; + +// +// The prehash version of the sign routine +success_flag key::sign( + unsigned char *signature, size_t len_signature_buffer, + const unsigned char *message, size_t len_message, + const hash_type& hash, + const void *context, size_t len_context, + const random& rand) { + + // Check if the message length is what we expect + if (len_message != hash.length) { + return failure; + } + + // Do the actual signature + sign_flag s = sign_internal( + signature, len_signature_buffer, + 0x01, // Domain separator == "Prehashed" + context, len_context, + hash.oid, hash.oid_length, // Include the oid + message, len_message, rand); + + if (s == sign_success) { + return success; + } else { + return failure; // We don't bother reporting the failure reason + } +} + +// The C++ version of prehashed sign is in stl.cpp + +// +// The prehashed version of verify +success_flag key::verify( + const unsigned char *signature, size_t len_signature, + const void *message, size_t len_message, + const hash_type& hash, + const void *context, size_t len_context) { + + // Note: we don't check if the message length is the expected hash + // length. Should we? + + return verify_internal( signature, len_signature, + 0x01, // Domain separator == "Prehashed" + context, len_context, + hash.oid, hash.oid_length, // Include the oid + message, len_message ); +} + +} /* namespace slh_dsa */ diff --git a/rdrand.cpp b/rdrand.cpp index a4ad067..6755ac1 100644 --- a/rdrand.cpp +++ b/rdrand.cpp @@ -7,7 +7,7 @@ /// \file rdrand.cpp /// \brief This contains the routine to get randomness using rdrand_fill -namespace sphincs_plus { +namespace slh_dsa { /// /// Call rdrand to fill the buffer with randomness @@ -40,4 +40,4 @@ success_flag rdrand_fill( void* target, size_t bytes_to_fill) { return success; } -} /* namespace sphincs_plus */ +} /* namespace shl_dsa */ diff --git a/read.me b/read.me index d5627a1..de0330e 100644 --- a/read.me +++ b/read.me @@ -1,13 +1,12 @@ -Sphincs+ is a signature cryptosystem that was submitted to the NIST -Postquantum Standardization; it was accepted as a Round 3 Alternate. -It has the most conservative security assumption of all candidates -(essentially, the second preimage resistance of the underlying hash function, -which appears to be a safer assumption than any other; in particular, any -signature method that first hashes the message, and then generates the -signature based on that hash needs to include a security assumption of that -hash - Sphincs+ makes no other security assumptions). However, on the -drawback side, Sphincs+ signatures and the signature generation time are both -large (which is why it is an alternate). +SLH-DSA is a NIST approved (FIPS 205) postquantum signature cryptosystem. + +It has the most conservative security assumption of all (essentially, the +second preimage resistance of the underlying hash function, which appears to +be a safer assumption than any other; in particular, any signature method that +first hashes the message, and then generates the signature based on that hash +needs to include a security assumption of that hash - SLH-DSA makes no other +security assumptions). However, on the drawback side, SLH-DSA signatures and +the signature generation time are both large. This package attempts to reduce one of the drawbacks (namely, the signature generation time; we can't reduce the signature size without breaking @@ -18,9 +17,8 @@ Here is how this package is used: - Step 1: define an object that denotes the key, as in: - sphincs_plus::key_sha256_128s_simple signer; // This says we're using - // the SPHINCS+-SHA-256-128s-simple parameter set - // There are classes for all 36 parameter sets + slh_dsa::key_sha2_128s signer; // This says we're using the SHA2-128s + // parameter set. There are classes for all 12 parameter sets - Step 2: give the signer a key. Here are the possible options: @@ -36,32 +34,36 @@ Here is how this package is used: Notes: - priv_key is a byte array containing the private key in the format - specified in the Sphincs+ documentation + specified in FIPS 205 - Load an existing public key (if all you need to do is verify) signer.set_public_key(public_key); Notes: - public_key is a byte array containing the public key in the format - specified in the Sphincs+ documentation + specified in FIPS 205 - Step 3: sign a message; we provide two separate interfaces to do this: - Option 1: the C-type interface if (!signer.sign(signature, len_signature_buffer, - message, len_message, + message, len_message, context, len_context, rand)) handle_failure(); Notes: - signature is the buffer where the signature to be placed - len_signature_buffer is the length of the above buffer (and we'll fail if the buffer isn't big enough). - message, len_message is the message (and length) to sign + - context, len_context is the signature context (and it is + optional - omitting it has the signer to default to an empty + context) - rand is a function that returns randomness (and it is optional in this case - omiting it has the signer default to rdrand; passing 0 means the signer will fall back to determanistic mode) - Option 2: the C++-style interface - auto sig = signer.sign(message, len_message, rand); + auto sig = signer.sign(message, len_message, + context, len_context, rand); Notes: - This allocates and returns the signature as a unique_ptr; sig.get() @@ -69,22 +71,43 @@ Here is how this package is used: be freed when sig goes out of scope. - This call throws an exception on error (e.g. if the signer doesn't have a key) + - context, len_context is the signature context (and it is + optional - omitting it has the signer to default to an empty + context) - rand is a function that returns randomness (and it is optional in this case - omiting it has the signer default to rdrand; passing 0 means the signer will fall back to determanistic mode) The call signer.len_signature() will retrieve the signature length + In addition, in both cases, you can also insert a hash_type immediately + after the message length. This would specify that you are doing the + prehash version (HashSLH-DSA in FIPS 205 terms). If you do so, this + API assumes you have already hashed the message, and that the 'message' + that you're passing here is actually the hash (and len_message is the + length of the hash). + - Step 4: verify a signature bool success = signer.verify( signature, len_signature, - message, len_message ); + message, len_message, + context, len_context ); Notes: - signature is the buffer holding the signature - len_signature is the length of the signature - message, len_message is the message (and length) to verify + - context, len_context is the signature context (and it is + optional - omitting it has the signer to default to an empty + context) - this returns true if the signature verifies, false if not + In addition, in both cases, you can also insert a hash_type immediately + after the message length. This would specify that you are doing the + prehash version (HashSLH-DSA in FIPS 205 terms). If you do so, this + API assumes you have already hashed the message, and that the 'message' + that you're passing here is actually the hash (and len_message is the + length of the hash). + - Other useful interfaces: - signer.len_signature(), signer.len_public_key(), signer.len_private_key() returns the lengths of the generated @@ -98,21 +121,21 @@ Here is how this package is used: while generating a signature; passing a 1 signifies that we shouldn't spawn any child threads; it is also subject to a sane maximum. - - All key classes (such as key_sha256_128s_simple) are subclasses of - a master sphincs_plus::key class, this logic works as expected: - sphincs_key::key* k; - if (i_am_in_a_haraka_mood) - k = new sphincs_plus::key_haraka_128s_simple; - else if (perhaps_sha_would_be_better) - k = new sphincs_plus::key_sha256_128s_simple; - else - k = new sphincs_plus::key_shake256_128s_simple; + - All key classes (such as sha2_128s) are subclasses of a master + slh_dsa::key class, this logic works as expected: + slh_dsa::key* k; + if (i_am_in_a_slow_mood) + k = new slh_dsa::key_sha2_128s; + else if (perhaps_faster_would_be_better) + k = new slh_dsa::key_sha2_128f; + else /* I think I prefer shake */ + k = new slh_dsa::key_shake_128s; k->generate_key_pair(); Some comments: -- This package is not meant to replace the Sphincs+ reference code, +- This package is not meant to replace the SLH-DSA reference code, but to supplement it. This means that this package doesn't have to meet all the requirements that the reference code does (e.g. it doesn't have to run everywhere). @@ -164,34 +187,51 @@ Some comments: - Once again, a matter of taste, but I find the naming convention that NIST used unintutitive; to me, crypto_sign_open doesn't denote 'verify'. I renamed things to be more to my taste. + - The original code actually implemented Sphincs+. Since SLH-DSA is now + official, I changed things to adapt to that (by supporting the additional + features of SLH-DSA, namely contexts and prehashing; by dropping the + parameter sets no longer supported by SLH-DSA, namely the robust and + Haraka parameter sets, and by renaming things to be slh_dsa (some of the + internal filenames still refer to sphincs - they're internal only, so + I didn't bother changing them). + - And, since this is C++, I put most everything (there's a bit of C code) + in a dedicated slh_dsa namespace. + - Some of this code originally came from the Sphincs+ reference code; however I made a number of tweaks, both to match the different environment (e.g. being able to support multiple parameter sets at once, or to avoid VLAs which C++ doesn't like, to support the different API) and most importantly because I felt like it. -- I included a regression test package (test_sphincs); it has a number of +- I included a regression test package (test_slh_dsa); it has a number of options; the quickest way is to do: - make test_sphincs - test_sphincs all + make test_slh_dsa + slh_dsa all which will run all the tests it has on a representative sample of parameter sets. Design decisions: - I made the API using C++, rather than C; that provides us options - (namespaces, classes, virtual functions) that makes things considerably - cleaner; the logic depends heavily on virtual functions. - - I aimed to making this package as interoperable as possible to the - Sphincs+ reference code; in particular, the private keys have the same - format (and are generated by the same randomness, and correspond to the - same public keys). One issue this causes is that the private key doesn't - contain any information about the parameter set used; this implies that - the API must have the caller specify the parameter set, and there's - nothing preventing you from trying to load (say) a 128f-sha256-robust - private key into one that expects 128s-shake256-simple. This is not - ideal; however I can't think of a better option that would not break key - compatibility. - - I decided to support all the various Sphincs+ parameter sets (even the - ones that appear somewhat pointless, such as L5+Haraka). + (namespaces, classes, virtual functions, function name overloading) that + makes things considerably cleaner; the logic depends heavily on virtual + functions. + - I aimed to making this package implement FIPS 205; in particular, the + private keys have the same format (and are generated by the same + randomness, and correspond to the same public keys). One issue this + causes is that the private key doesn't contain any information about the + parameter set used; this implies that the API must have the caller specify + the parameter set, and there's nothing preventing you from trying to load + (say) a 128f-sha2 private key into one that expects 128s-shake. This is + not ideal; however that's what FIPS 205 specifies. + - I decided not to implement the internal interface. This is because such + an interface would allow somebody to be able to extract information which + would allow them to generate forgeries (and while we need to trust the + application requesting us to sign somewhat, I don't like to trust them + to that extent). This is specific to SLH-DSA; ML-DSA does not have the + same issue, and so the internal interface is safe there. + - I predefine the four prehash types defined within FIPS 205 (SHA2-256, + SHA2-512, SHAKE-128, SHAKE-256). NIST has since defined other OIDs for + other hash types; however I rather doubt anyone would have prehash in the + first place, so I didn't bother. - I decided to avoid globals; all memory is within the class object or within automatics. - I decided to always use the AVX2/AES_NI instructions to accelerate things; @@ -201,7 +241,7 @@ Design decisions: banging on their AVX2 microengines at the same time... - This package is written in C++, the features we use are namespaces (so we can avoid namespace collisions without having to prefix everything - with "sphincs"; otherwise, I would never have a class with as generic + with "slh_dsa"; otherwise, I would never have a class with as generic a name as "key"), and classes (which we use to select the parameter set, as well as give us convienent place to place expanded keys and whatnot. We don't use any of the more advanced features, such as RTTI; we do use diff --git a/sha256.cpp b/sha256.cpp index 473120a..de61efe 100644 --- a/sha256.cpp +++ b/sha256.cpp @@ -15,7 +15,7 @@ #include "sha256.h" #include "internal.h" -namespace sphincs_plus { +namespace slh_dsa { const unsigned SHA256_FINALCOUNT_SIZE = 8; const unsigned NUM_ROUNDS = 64; @@ -191,5 +191,5 @@ void SHA256_CTX::export_intermediate(sha256_state intermediate) { memcpy( intermediate, h, 8 * sizeof(uint32_t) ); } -} /* namespace sphincs_plus */ +} /* namespace slh_dsa */ diff --git a/sha256.h b/sha256.h index a06d9d1..9c4f4e4 100644 --- a/sha256.h +++ b/sha256.h @@ -8,7 +8,7 @@ /// \file sha256.h /// \brief The definitions of the low level SHA256 classes -namespace sphincs_plus { +namespace slh_dsa { typedef uint32_t sha256_state[8]; // #include "api.h" @@ -10,10 +8,10 @@ #include "sha256avx.h" #include "mgf1.h" -namespace sphincs_plus { +namespace slh_dsa { // This precomputes the SHA-256 hash state after processing the public seed -void sha256_hash::initialize_public_seed(const unsigned char *pub_seed) { +void key_sha2::initialize_public_seed(const unsigned char *pub_seed) { uint8_t block[sha256_block_size]; size_t i; size_t n = len_hash(); @@ -31,12 +29,12 @@ void sha256_hash::initialize_public_seed(const unsigned char *pub_seed) { ctx.export_intermediate( state_seeded ); } -void sha256_hash::set_public_key(const unsigned char *public_key) { +void key_sha2::set_public_key(const unsigned char *public_key) { key::set_public_key(public_key); initialize_public_seed( get_public_seed() ); } -void sha256_hash::set_private_key(const unsigned char *private_key) { +void key_sha2::set_private_key(const unsigned char *private_key) { key::set_private_key(private_key); initialize_public_seed( get_public_seed() ); } @@ -45,7 +43,7 @@ void sha256_hash::set_private_key(const unsigned char *private_key) { * 8-way parallel version of prf_addr; takes 8x as much input and output * This is SHA-256 specific */ -void sha256_hash::prf_addr_xn(unsigned char **out, +void key_sha2::prf_addr_xn(unsigned char **out, const addr_t* addrx8) { __m256i outbufx8[8][sha256_output_size / sizeof(__m256i)]; @@ -98,8 +96,11 @@ void sha256_hash::prf_addr_xn(unsigned char **out, } // prf_msg is defined as HMAC( prf, opt_rand || msg ) -void sha256_hash::prf_msg( unsigned char *result, +void key_sha2::prf_msg( unsigned char *result, const unsigned char *opt_rand, + unsigned char domain_separator_byte, + const void *context, size_t len_context, + const void *oid, size_t len_oid, const unsigned char *msg, size_t len_msg ) { SHA256_CTX ctx; unsigned char block[sha256_block_size]; @@ -115,6 +116,15 @@ void sha256_hash::prf_msg( unsigned char *result, memset( &block[n], 0x36, sha256_block_size-n ); ctx.update( block, sha256_block_size ); ctx.update( opt_rand, n ); + ctx.update( &domain_separator_byte, 1 ); + unsigned char c = len_context; + ctx.update( &c, 1 ); + if (len_context > 0) { + ctx.update( context, len_context ); + } + if (len_oid > 0) { + ctx.update( oid, len_oid ); + } ctx.update( msg, len_msg ); ctx.final(hash_output); @@ -137,9 +147,12 @@ void sha256_hash::prf_msg( unsigned char *result, // Here, len_result is not the size of the buffer (which it is in most // similar contexts); instead, it is the number of output bytes desired -void sha256_hash::h_msg( unsigned char *result, size_t len_result, +void key_sha2::h_msg( unsigned char *result, size_t len_result, const unsigned char *r, - const unsigned char *msg, size_t len_msg ) { + unsigned char domain_separator_byte, + const void *context, size_t len_context, + const void *oid, size_t len_oid, + const void *msg, size_t len_msg ) { unsigned char msg_hash[ sha256_output_size + 2*max_len_hash ]; size_t n = len_hash(); @@ -151,6 +164,15 @@ void sha256_hash::h_msg( unsigned char *result, size_t len_result, ctx.update(r, n); ctx.update(pk_seed, n); ctx.update(pk_root, n); + ctx.update(&domain_separator_byte, 1); + unsigned char c = len_context; + ctx.update( &c, 1 ); + if (len_context > 0) { + ctx.update(context, len_context); + } + if (len_oid > 0) { + ctx.update(oid, len_oid); + } ctx.update(msg, len_msg); ctx.final(msg_hash + 2*n); @@ -161,15 +183,15 @@ void sha256_hash::h_msg( unsigned char *result, size_t len_result, stream.output( result, len_result ); } -unsigned sha256_hash::num_track(void) { +unsigned key_sha2::num_track(void) { return 8; } -unsigned sha256_hash::num_log_track(void) { +unsigned key_sha2::num_log_track(void) { return 3; } -sha256_hash::sha256_hash(void) { - // We initialize the offset parameters to SHA-256 specific values +key_sha2::key_sha2(void) { + // We initialize the offset parameters to SHA-2 specific values offset_layer = 0; offset_tree = 1; offset_type = 9; @@ -181,4 +203,4 @@ sha256_hash::sha256_hash(void) { offset_tree_index = 18; } -} /* namespace sphincs_plus */ +} /* namespace slh_dsa */ diff --git a/sha256_robust.cpp b/sha256_robust.cpp deleted file mode 100644 index 7b9a1c1..0000000 --- a/sha256_robust.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* - * This file has support for the low level SHA-256-robust routines - */ -#include -#include "api.h" -#include "internal.h" -#include "sha256avx.h" -#include "sha256.h" -#include "mgf1.h" -#include "mgf1_8x.h" - -namespace sphincs_plus { - -/** - * The robust version of thash - */ -void key_sha256_robust::thash( unsigned char* out, - const unsigned char* in, - unsigned int inblocks, addr_t addr) { - unsigned char outbuf[sha256_output_size]; - unsigned n = len_hash(); - - // Retrieve precomputed state containing pub_seed - SHA256_CTX ctx; - ctx.init_from_intermediate(state_seeded, sha256_block_size); - - // Initialize the seed for the MGF1 engine - unsigned char mgf1_seed[ max_len_hash + sha256_addr_bytes ]; - memcpy( mgf1_seed, get_public_seed(), n ); - memcpy( &mgf1_seed[n], addr, sha256_addr_bytes ); - mgf1 bitstream( mgf1_seed, n + sha256_addr_bytes ); - - // Starting at state_seeded, hash the addr structure and the - // input blocks xored with the mgf1 stream - ctx.update(addr, sha256_addr_bytes); - for (unsigned i = 0; i < inblocks; i++) { - unsigned char buffer[max_len_hash]; - bitstream.output( buffer, n ); - for (unsigned j = 0; j < n; j++) { - buffer[j] ^= *in++; - } - ctx.update(buffer, n ); - } - ctx.final(outbuf); - - memcpy(out, outbuf, len_hash()); -} - -/** - * 8-way parallel version of thash; takes 8x as much input and output - */ -void key_sha256_robust::thash_xn(unsigned char **out, - unsigned char **in, - unsigned int inblocks, - addr_t* addrx8) -{ - sha256ctx8x ctx; - int n = len_hash(); - - sha256_init_frombytes_x8(&ctx, state_seeded, 512); - - sha256_update8x(&ctx, - &addrx8[0], - &addrx8[1], - &addrx8[2], - &addrx8[3], - &addrx8[4], - &addrx8[5], - &addrx8[6], - &addrx8[7], - sha256_addr_bytes ); - - // Fire up the MGF1 engine - unsigned char *ptr_seed[8]; - unsigned char seed[ 8*(max_len_hash + sha256_addr_bytes) ]; - for (int i=0; i<8; i++) { - ptr_seed[i] = &seed[ i * (max_len_hash+sha256_addr_bytes) ]; - memcpy( ptr_seed[i], get_public_seed(), n ); - memcpy( ptr_seed[i]+n, &addrx8[i], sha256_addr_bytes ); - } - mgf1_8x bit_stream( ptr_seed, n + sha256_addr_bytes ); - - unsigned char buffer[8][max_len_hash]; - unsigned char *ptr_buffer[8]; - for (int i=0; i<8; i++) { - ptr_buffer[i] = buffer[i]; - } - for (unsigned k=0, block=0; k #include "api.h" @@ -7,12 +7,12 @@ #include "sha256avx.h" #include "sha256.h" -namespace sphincs_plus { +namespace slh_dsa { /** - * The simple version of thash + * The SHA-2 version of thash */ -void key_sha256_simple::thash( unsigned char *out, +void key_sha2::thash( unsigned char *out, const unsigned char *in, unsigned int inblocks, addr_t addr) { unsigned char outbuf[sha256_output_size]; @@ -33,7 +33,7 @@ void key_sha256_simple::thash( unsigned char *out, /** * 8-way parallel version of thash; takes 8x as much input and output */ -void key_sha256_simple::thash_xn(unsigned char **out, +void key_sha2::thash_xn(unsigned char **out, unsigned char **in, unsigned int inblocks, addr_t* addrx8) @@ -86,4 +86,4 @@ void key_sha256_simple::thash_xn(unsigned char **out, memcpy(out[7], outbufx8[7], n); } -} /* sphincs_plus */ +} /* slh_dsa */ diff --git a/sha256avx.cpp b/sha256avx.cpp index 802c54f..c5e10e9 100644 --- a/sha256avx.cpp +++ b/sha256avx.cpp @@ -4,7 +4,7 @@ #include "sha256avx.h" -namespace sphincs_plus { +namespace slh_dsa { // Transpose 8 vectors containing 32-bit values static void transpose(u256 s[8]) { @@ -314,4 +314,4 @@ void sha256_transform8x(sha256ctx8x *ctx, const unsigned char *data) { ctx->s[7] = ADD32(s[7], ctx->s[7]); } -} /* namespace sphincs_plus */ +} /* namespace slh_dsa */ diff --git a/sha256avx.h b/sha256avx.h index 4d4877d..e108034 100644 --- a/sha256avx.h +++ b/sha256avx.h @@ -3,7 +3,7 @@ #include #include "immintrin.h" -namespace sphincs_plus { +namespace slh_dsa { static const unsigned int RC[] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, @@ -97,6 +97,6 @@ void sha256_final8x(sha256ctx8x *ctx, void sha256_transform8x(sha256ctx8x *ctx, const unsigned char *data); -} /* sphincs_plus */ +} /* namespace slh_dsa */ #endif diff --git a/sha512.cpp b/sha512.cpp index 0a1d75a..e2f6ce5 100644 --- a/sha512.cpp +++ b/sha512.cpp @@ -15,7 +15,7 @@ #include #include "sha512.h" -namespace sphincs_plus { +namespace slh_dsa { static void put_bigendian( unsigned char *target, uint64_t value, size_t bytes ) { @@ -222,4 +222,4 @@ void SHA512_CTX::export_intermediate(sha512_state intermediate) { memcpy( intermediate, h, 8 * sizeof(uint64_t) ); } -} /* namespace sphincs_plus */ +} /* namespace slh_dsa */ diff --git a/sha512.h b/sha512.h index 8f6d2e1..06b1904 100644 --- a/sha512.h +++ b/sha512.h @@ -8,7 +8,7 @@ /// \file sha512.h /// \brief The definitions of the low level SHA512 classes -namespace sphincs_plus { +namespace slh_dsa { const unsigned sha512_block_size = 128; // -#include "api.h" -#include "internal.h" -#include "sha512avx.h" -#include "sha512.h" -#include "mgf1.h" -#include "mgf1_512_4x.h" - -namespace sphincs_plus { - -static void xor_mem(unsigned char* dest, const unsigned char* src, unsigned n) { - while (n--) - *dest++ ^= *src++; -} - -/** - * The robust version of thash - */ -void key_sha256_L35_robust::thash( unsigned char *out, - const unsigned char *in, - unsigned int inblocks, addr_t addr) { - // thash is never called with inblocks==1, hence we don't need to - // special case that - - unsigned char outbuf[sha512_output_size]; - unsigned n = len_hash(); - - // Retrieve precomputed state containing pub_seed - SHA512_CTX ctx; - ctx.init_from_intermediate(state_seeded_512, sha512_block_size); - - // Initialize the seed for the MGF1 engine - unsigned char mgf1_seed[ max_len_hash + sha256_addr_bytes ]; - memcpy( mgf1_seed, get_public_seed(), n ); - memcpy( &mgf1_seed[n], addr, sha256_addr_bytes ); - mgf1 bitstream( mgf1_seed, n + sha256_addr_bytes ); - - // Starting at state_seeded, hash the addr structure and the - // input blocks xored with the mgf1 stream - ctx.update(addr, sha256_addr_bytes); - for (unsigned i = 0; i < inblocks; i++) { - unsigned char buffer[max_len_hash]; - bitstream.output( buffer, n ); - xor_mem(buffer, in, n); - in += n; - ctx.update( buffer, n ); - } - ctx.final(outbuf); - - memcpy(out, outbuf, len_hash()); -} - -/** - * 8-way parallel version of thash; takes 8x as much input and output - * Note that, for inblocks==1, the alternative f_xn function is used - */ -void key_sha256_L35_robust::thash_xn(unsigned char **out, - unsigned char **in, - unsigned int inblocks, - addr_t* addrx8) -{ - sha512ctx4x ctx; - int n = len_hash(); - unsigned char *mask_seed[4]; - unsigned char seed[ 4*(max_len_hash + sha256_addr_bytes) ]; - for (int j=0; j<4; j++) { - mask_seed[j] = &seed[ j * (max_len_hash+sha256_addr_bytes) ]; - } - unsigned char buffer[4][max_len_hash]; - unsigned char *ptr_buffer[4]; - for (int j=0; j<4; j++) { - ptr_buffer[j] = buffer[j]; - } - __m256i outbufx8[8][sha512_output_size / sizeof(__m256i)]; - - // Note: the API says '8-way', however the SHA512-AVX2 code we have - // does '4-way'. Account for this by iterating through the AVX2 code - // twice - for (int i=0; i<8; i+=4) { - - sha512_init_frombytes_x4(&ctx, state_seeded_512, 1024); - - sha512_update4x(&ctx, - &addrx8[i+0], - &addrx8[i+1], - &addrx8[i+2], - &addrx8[i+3], - sha256_addr_bytes ); - - // Fire up the MGF1 engine that'll generate the masks - for (int j=0; j<4; j++) { - memcpy( mask_seed[j], get_public_seed(), n ); - memcpy( mask_seed[j]+n, &addrx8[i+j], sha256_addr_bytes ); - } - mgf1_sha512_4x bit_stream( mask_seed, n + sha256_addr_bytes ); - - // Stir in the input blocks (including the mask) - for (unsigned k=0, block=0; k #include "api.h" @@ -7,12 +7,12 @@ #include "sha512avx.h" #include "sha512.h" -namespace sphincs_plus { +namespace slh_dsa { /** - * The simple version of thash + * The L3, L5 version of thash */ -void key_sha256_L35_simple::thash( unsigned char *out, +void key_sha2_L35::thash( unsigned char *out, const unsigned char *in, unsigned int inblocks, addr_t addr) { // thash is never called with inblocks==1, hence we don't need to @@ -37,7 +37,7 @@ void key_sha256_L35_simple::thash( unsigned char *out, * 8-way parallel version of thash; takes 8x as much input and output * Note that, for inblocks==1, the alternative f_xn function is used */ -void key_sha256_L35_simple::thash_xn(unsigned char **out, +void key_sha2_L35::thash_xn(unsigned char **out, unsigned char **in, unsigned int inblocks, addr_t* addrx8) { @@ -82,13 +82,13 @@ void key_sha256_L35_simple::thash_xn(unsigned char **out, // // For the single input version of T, fall back to the base version, which // uses SHA-256 -void key_sha256_L35_simple::f_xn(unsigned char **out, unsigned char **in, +void key_sha2_L35::f_xn(unsigned char **out, unsigned char **in, addr_t* addrxn) { - key_sha256_simple::thash_xn(out, in, 1, addrxn); + key_sha2::thash_xn(out, in, 1, addrxn); } // This precomputes the SHA-512 hash state after processing the public seed -void key_sha256_L35_simple::initialize_public_seed(const unsigned char *pub_seed) { +void key_sha2_L35::initialize_public_seed(const unsigned char *pub_seed) { uint8_t block[sha512_block_size]; size_t i; size_t n = len_hash(); @@ -106,7 +106,7 @@ void key_sha256_L35_simple::initialize_public_seed(const unsigned char *pub_seed ctx.export_intermediate( state_seeded_512 ); // Also initialize the SHA-256 initial hash (which we also use) - sha256_hash::initialize_public_seed(pub_seed); + key_sha2::initialize_public_seed(pub_seed); } -} /* sphincs_plus */ +} /* slh_dsa */ diff --git a/sha512avx.cpp b/sha512avx.cpp index 20ad928..ff73802 100644 --- a/sha512avx.cpp +++ b/sha512avx.cpp @@ -4,7 +4,7 @@ #include "sha512avx.h" -namespace sphincs_plus { +namespace slh_dsa { typedef uint64_t u64; typedef __m256i u256; @@ -348,4 +348,4 @@ static void sha512_transform4x(sha512ctx4x *ctx, const unsigned char *data) { ctx->s[7] = ADD64(s7, ctx->s[7]); } -} /* namespace sphincs_plus */ +} /* namespace slh_dsa */ diff --git a/sha512avx.h b/sha512avx.h index abc7aa9..040f254 100644 --- a/sha512avx.h +++ b/sha512avx.h @@ -3,7 +3,7 @@ #include #include "immintrin.h" -namespace sphincs_plus { +namespace slh_dsa { typedef struct SHA512state4x { __m256i s[8]; @@ -27,6 +27,6 @@ void sha512_final4x(sha512ctx4x *ctx, __m256i out2[2], __m256i out3[2]); -} /* sphincs_plus */ +} /* slh_dsa */ #endif diff --git a/shake256_hash.cpp b/shake256_hash.cpp index 8b7fa13..7392a85 100644 --- a/shake256_hash.cpp +++ b/shake256_hash.cpp @@ -9,13 +9,13 @@ #include "fips202.h" #include "fips202x4.h" -namespace sphincs_plus { +namespace slh_dsa { /* * 4-way parallel version of prf_addr; takes 4x as much input and output * This is SHAKE-256 specific */ -void shake256_hash::prf_addr_xn(unsigned char **out, +void key_shake::prf_addr_xn(unsigned char **out, const addr_t* addrx4) { SHAKE256_4X_CTX ctx; @@ -41,8 +41,11 @@ void shake256_hash::prf_addr_xn(unsigned char **out, } // prf_msg is defined as SHAKE256( prf || optrand || msg ) -void shake256_hash::prf_msg( unsigned char *result, +void key_shake::prf_msg( unsigned char *result, const unsigned char *opt_rand, + unsigned char domain_separator_byte, + const void *context, size_t len_context, + const void *oid, size_t len_oid, const unsigned char *msg, size_t len_msg ) { SHAKE256_CTX ctx; unsigned n = len_hash(); @@ -51,6 +54,11 @@ void shake256_hash::prf_msg( unsigned char *result, shake256_inc_absorb(&ctx, get_prf(), n); shake256_inc_absorb(&ctx, opt_rand, n); + shake256_inc_absorb(&ctx, &domain_separator_byte, 1 ); + unsigned char c = len_context; + shake256_inc_absorb(&ctx, &c, 1 ); + if (context) shake256_inc_absorb(&ctx, static_cast(context), len_context ); + if (oid) shake256_inc_absorb(&ctx, static_cast(oid), len_oid ); shake256_inc_absorb(&ctx, msg, len_msg); shake256_inc_finalize(&ctx); @@ -60,9 +68,12 @@ void shake256_hash::prf_msg( unsigned char *result, // Here, len_result is not the size of the buffer (which it is in most // similar contexts); instead, it is the number of output bytes desired -void shake256_hash::h_msg( unsigned char *result, size_t len_result, +void key_shake::h_msg( unsigned char *result, size_t len_result, const unsigned char *r, - const unsigned char *msg, size_t len_msg ) { + unsigned char domain_separator_byte, + const void *context, size_t len_context, + const void *oid, size_t len_oid, + const void *msg, size_t len_msg ) { SHAKE256_CTX ctx; unsigned n = len_hash(); @@ -74,7 +85,12 @@ void shake256_hash::h_msg( unsigned char *result, size_t len_result, shake256_inc_absorb(&ctx, r, n); shake256_inc_absorb(&ctx, pk_seed, n); shake256_inc_absorb(&ctx, pk_root, n); - shake256_inc_absorb(&ctx, msg, len_msg); + shake256_inc_absorb(&ctx, &domain_separator_byte, 1 ); + unsigned char c = len_context; + shake256_inc_absorb(&ctx, &c, 1 ); + if (context) shake256_inc_absorb(&ctx, static_cast(context), len_context ); + if (oid) shake256_inc_absorb(&ctx, static_cast(oid), len_oid ); + shake256_inc_absorb(&ctx, static_cast(msg), len_msg); shake256_inc_finalize(&ctx); @@ -83,21 +99,21 @@ void shake256_hash::h_msg( unsigned char *result, size_t len_result, // // Scurry away copies of the public and secret seeds -void shake256_hash::set_public_key(const unsigned char *public_key) { +void key_shake::set_public_key(const unsigned char *public_key) { key::set_public_key(public_key); shake256_precompute( &pre_pub_seed, get_public_seed(), len_hash() ); } -void shake256_hash::set_private_key(const unsigned char *private_key) { +void key_shake::set_private_key(const unsigned char *private_key) { key::set_private_key(private_key); shake256_precompute( &pre_pub_seed, get_public_seed(), len_hash() ); } -unsigned shake256_hash::num_track(void) { +unsigned key_shake::num_track(void) { return 4; } -unsigned shake256_hash::num_log_track(void) { +unsigned key_shake::num_log_track(void) { return 2; } -} /* namespace sphincs_plus */ +} /* namespace slh_dsa */ diff --git a/shake256_robust.cpp b/shake256_robust.cpp deleted file mode 100644 index e37da37..0000000 --- a/shake256_robust.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * This file has support for the low level SHAKE-256-robust routines - */ -#include -#include "api.h" -#include "internal.h" -#include "fips202.h" -#include "fips202x4.h" - -namespace sphincs_plus { - -/** - * The robust version of thash - */ -void key_shake256_robust::thash( unsigned char *out, - const unsigned char *in, - unsigned int inblocks, addr_t addr) { - unsigned n = len_hash(); - SHAKE256_CTX mask_ctx; - SHAKE256_CTX ctx; - - shake256_inc_init_from_precompute(&mask_ctx, &pre_pub_seed ); - shake256_inc_absorb(&mask_ctx, addr, addr_bytes); - shake256_inc_finalize(&mask_ctx); - - shake256_inc_init_from_precompute(&ctx, &pre_pub_seed ); - shake256_inc_absorb(&ctx, addr, addr_bytes); - for (unsigned i=0; i> shift; } -// -// The function that generates a signature +/// +/// This is the signature API that we use almost all the time +/// The logic is simple, and so we put it here success_flag key::sign( - unsigned char* signature, size_t len_signature_buffer, - const unsigned char* message, size_t len_message, - const random& rand) { + unsigned char *signature, size_t len_signature_buffer, + const unsigned char *message, size_t len_message, + const void *context, size_t len_context, + const random& rand) { + + sign_flag result = sign_internal(signature, len_signature_buffer, 0x0, + context, len_context, 0, 0, + message, len_message, rand); + if (result == sign_success) { + return success; + } else { + return failure; // We don't bother reporting the failure reason + } +} + +// +// The internal function that generates a signature +key::sign_flag key::sign_internal( + unsigned char *signature, size_t len_signature_buffer, + unsigned char domain_separator_byte, + const void *context, size_t len_context, + const void *oid, size_t len_oid, + const unsigned char *message, size_t len_message, + const random& rand) { + // Make sure this key has the private key loaded - if (!have_private_key) return false; + if (!have_private_key) return sign_no_private_key; + + // Make sure the context isn't too long + if (len_context > 255) return sign_bad_context_len; size_t n = len_hash(); unsigned i; @@ -250,7 +276,7 @@ success_flag key::sign( // Now, check if the buffer we were given is long enough if (signature_length > len_signature_buffer) { - return failure; // Buffer overflow - just say no + return sign_buffer_too_short; // Buffer overflow - just say no } // Step 2 - generate the randomness @@ -266,11 +292,13 @@ success_flag key::sign( // use the default } prf_msg( &signature[ geo.randomness_offset ], - opt, message, len_message ); + opt, domain_separator_byte, context, len_context, oid, len_oid, + message, len_message ); // Step 3 - hash the message hash_message( geo, &signature[ geo.randomness_offset ], - message, len_message ); + domain_separator_byte, context, len_context, oid, len_oid, + message, len_message ); // Step 4-: now it's time to schedule the various tasks that will // need to be done to generate the signature. First, compute how @@ -346,7 +374,7 @@ success_flag key::sign( } // All the works been done - declare victory - return success; + return sign_success; } // @@ -593,4 +621,4 @@ void task::hash_fors(work_center *w) { w->enqueue(this); } -} /* namespace sphincs_plus */ +} /* namespace slh_dsa */ diff --git a/slh-dsa-fast.cpp b/slh-dsa-fast.cpp new file mode 100644 index 0000000..c91ce45 --- /dev/null +++ b/slh-dsa-fast.cpp @@ -0,0 +1,160 @@ +#include +#include +#include "api.h" +#include "internal.h" + +/// \file slh-dsa-fast.cpp +/// \brief This contains various miscillaneous routines for SLH-DSA + +namespace slh_dsa { + +// Register the SLH-DSA geometry +// We expect that this is called only during construction +void key::set_geometry( size_t len_hash, size_t k, size_t t, + size_t h, size_t d, size_t wots_digits ) { + + len_hash_ = len_hash;; + k_ = k; + t_ = t; + h_ = h; + d_ = d; + wots_digits_ = wots_digits; + merkle_height_ = h/d; + wots_bytes_ = len_hash * wots_digits; +} + +void key::set_public_key(const unsigned char *public_key) { + memcpy( keys + PRIVKEY_PUBLICKEY_OFFSET * len_hash(), public_key, + LEN_PUBKEY * len_hash() ); + have_private_key = false; + have_public_key = true; +} + +void key::set_private_key(const unsigned char *private_key) { + memcpy( keys, private_key, LEN_PRIVKEY * len_hash() ); + have_private_key = true; + have_public_key = true; +} + +const unsigned char* key::get_public_key(void) { + if (!have_public_key) return 0; + return keys + PRIVKEY_PUBLICKEY_OFFSET * len_hash(); +} + +const unsigned char* key::get_private_key(void) { + if (!have_private_key) return 0; + return keys; +} + +/* Get the length of a public key */ +size_t key::len_public_key(void) { + /* The public key consists of two hash-length values */ + return LEN_PUBKEY * len_hash(); +} + +/* Get the length of a private key */ +size_t key::len_private_key(void) { + /* The private key consists of four hash-length values */ + return LEN_PRIVKEY * len_hash(); +} + +/* Get the length of a signature */ +size_t key::len_signature(void) { + return len_hash() * (1 + k() * (t()+1) + h() + d() * wots_digits()); +} + +/* Generate a public/private keypair */ +success_flag key::generate_key_pair(const random& rand) { + size_t n = len_hash(); + unsigned char priv_key[ LEN_PRIVKEY * max_len_hash ]; + + /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */ + switch (rand( priv_key, 3*n )) { + case random_success: break; + default: return failure; // On anything other than unqualified success + } + + /* Initialize our hash function with the private and public seeds */ + /* The root will be wrong - we'll fix that up later in this function */ + set_private_key(priv_key); + + /* Compute the root node of the top-most subtree */ + addr_t top_tree_addr = {0}; + addr_t wots_addr = {0}; + + /* We're computing the top level Merkle tree */ + set_layer_addr(top_tree_addr, d() - 1); + set_layer_addr(wots_addr, d() - 1); + + merkle_sign(NULL, priv_key + PRIVKEY_ROOT_OFFSET * n, + wots_addr, top_tree_addr, + ~0 /* ~0 means "don't bother generating an auth path */ ); + + /* And set our internal copy of the private key (now with the correct */ + /* root value) */ + set_private_key(priv_key); + + zeroize(priv_key, LEN_PRIVKEY * n); + + return success; +} + +// These functions don't have any error checking +const unsigned char* key::get_secret_seed(void) { + return keys + PRIVKEY_SECRETSEED_OFFSET * len_hash(); +} +const unsigned char* key::get_prf(void) { + return keys + PRIVKEY_PRF_OFFSET * len_hash(); +} +const unsigned char* key::get_public_seed(void) { + return keys + PRIVKEY_PUBLICSEED_OFFSET * len_hash(); +} +const unsigned char* key::get_root(void) { + return keys + PRIVKEY_ROOT_OFFSET * len_hash(); +} + +/// The default F function falls back to the thash +/// This is used for SHA-256 and SHAKE-256 - Haraka uses a different definition +void key::f_xn(unsigned char **out, unsigned char **in, addr_t* addrxn) { + thash_xn(out, in, 1, addrxn); +} + +/// The random generator we almost always use - ask the random number to +/// give us randomness +enum random_return random::operator()( void *target, size_t num_bytes ) const { + if (!func) return random_default; // No random function provided + if (success == func(target, num_bytes)) { + return random_success; + } else + return random_failure; +} + +/// Construct a key object (with no key yet). This only does the part of +/// the job that doesn't depend on the parameter set; the child contructor +/// will perform the rest +key::key(void) { + // We currently do not have either a public nor a private key pair + have_public_key = false; + have_private_key = false; + + // We initialize the offset parameters to what SHAKE uses + // SHA-256 will update these field values + offset_layer = 3; + offset_tree = 8; + offset_type = 19; + offset_kp_addr1 = 23; + offset_kp_addr2 = 22; + offset_chain_addr = 27; + offset_hash_addr = 31; + offset_tree_hgt = 27; + offset_tree_index = 28; + + num_thread = default_thread; +} + +key::~key(void) { + zeroize( keys, sizeof keys ); // We don't have to zeroize everything, + // however let's be thorough +} + +} /* namespace slh_dsa */ diff --git a/speed_test.cpp b/speed_test.cpp index ba1f8ae..a72f615 100644 --- a/speed_test.cpp +++ b/speed_test.cpp @@ -7,13 +7,15 @@ const unsigned ITER = 100; const unsigned MAX_THREAD = 16; +#if 0 +#error COMMAND ARGUMENTS NOT CURRENTLY SUPPORTED void usage(const char *programname) { fprintf( stderr, "Usage: %s [parmset]\n", programname ); fprintf( stderr, "Suported parmeter sets:\n" " sha128s sha128r sha192s sha192r sha256s sha256r\n" - " shake128s shake128r shake192s shake192r shake256s shake256r\n" - " har128s har128r har192s har192r har256s har256r\n" ); + " shake128s shake128r shake192s shake192r shake256s shake256r\n" ); } +#endif static int compare_float(const void *a, const void *b ) { const float *p = (const float *)a; @@ -23,7 +25,7 @@ static int compare_float(const void *a, const void *b ) { return 0; } -void run_test( sphincs_plus::key& k, const char *title ) { +void run_test( slh_dsa::key& k, const char *title ) { printf( "%s:\n", title ); if (!k.generate_key_pair()) { @@ -93,54 +95,27 @@ void run_test( sphincs_plus::key& k, const char *title ) { #define CONCAT( a, b ) a ## b int main(void) { #define TEST( PARM ) { \ - CONCAT( sphincs_plus::key_, PARM ) key; \ + CONCAT( slh_dsa::key_, PARM ) key; \ run_test( key, #PARM ); \ } - TEST( sha256_128f_simple ) - TEST( sha256_128f_robust ) - TEST( sha256_128s_simple ) - TEST( sha256_128s_robust ) - - TEST( shake256_128f_simple ) - TEST( shake256_128f_robust ) - TEST( shake256_128s_simple ) - TEST( shake256_128s_robust ) - - TEST( haraka_128f_simple ) - TEST( haraka_128f_robust ) - TEST( haraka_128s_simple ) - TEST( haraka_128s_robust ) - - TEST( sha256_192f_simple ) - TEST( sha256_192f_robust ) - TEST( sha256_192s_simple ) - TEST( sha256_192s_robust ) - - TEST( shake256_192f_simple ) - TEST( shake256_192f_robust ) - TEST( shake256_192s_simple ) - TEST( shake256_192s_robust ) - - TEST( haraka_192f_simple ) - TEST( haraka_192f_robust ) - TEST( haraka_192s_simple ) - TEST( haraka_192s_robust ) - - TEST( sha256_256f_simple ) - TEST( sha256_256f_robust ) - TEST( sha256_256s_simple ) - TEST( sha256_256s_robust ) - - TEST( shake256_256f_simple ) - TEST( shake256_256f_robust ) - TEST( shake256_256s_simple ) - TEST( shake256_256s_robust ) - - TEST( haraka_256f_simple ) - TEST( haraka_256f_robust ) - TEST( haraka_256s_simple ) - TEST( haraka_256s_robust ) + TEST( sha2_128f ) + TEST( sha2_128s ) + + TEST( shake_128f ) + TEST( shake_128s ) + + TEST( sha2_192f ) + TEST( sha2_192s ) + + TEST( shake_192f ) + TEST( shake_192s ) + + TEST( sha2_256f ) + TEST( sha2_256s ) + + TEST( shake_256f ) + TEST( shake_256s ) return 0; } diff --git a/stl.cpp b/stl.cpp index 7a5a893..c131c01 100644 --- a/stl.cpp +++ b/stl.cpp @@ -1,4 +1,5 @@ #include +#include #include "api.h" // @@ -8,23 +9,63 @@ // enough), and has a built in destructor (which will free the array when the // caller is done with it) -namespace sphincs_plus { +namespace slh_dsa { std::unique_ptr key::sign( const unsigned char *message, size_t len_message, + const void *context, size_t len_context, const random& rand) { size_t sig_len = len_signature(); std::unique_ptrsignature( new unsigned char[sig_len] ); - success_flag worked = sign(signature.get(), sig_len, - message, len_message, rand); + sign_flag flag = sign_internal(signature.get(), sig_len, + 0x00, // Not prehashed + context, len_context, + 0, 0, // No hash OID + message, len_message, rand); - if (worked != success) { - throw std::runtime_error( "no Sphincs+ private key" ); // The only - // possible reason sign would generate an error + switch (flag) { + case sign_success: + return signature; + case sign_no_private_key: + throw std::runtime_error( "no SLH-DSA private key" ); + case sign_bad_context_len: + throw std::runtime_error( "bad context" ); + default: + throw std::runtime_error( "unknown error" ); + } +} + +// And the prehash version +std::unique_ptr key::sign( + const unsigned char *message, size_t len_message, + const hash_type& hash, + const void *context, size_t len_context, + const random& rand) { + if (len_message != hash.length) { + // We insist that the length of the hash be what we expect + throw std::runtime_error( "bad hash length" ); } - return signature; + size_t sig_len = len_signature(); + std::unique_ptrsignature( new unsigned char[sig_len] ); + + sign_flag flag = sign_internal(signature.get(), sig_len, + 0x01, // Prehashed + context, len_context, + hash.oid, hash.oid_length, // The hash OID + message, len_message, rand); + + switch (flag) { + case sign_success: + return signature; + case sign_no_private_key: + throw std::runtime_error( "no SLH-DSA private key" ); + case sign_bad_context_len: + throw std::runtime_error( "bad context" ); + default: + throw std::runtime_error( "unknown error" ); + } } -} /* namespace sphincs_plus */ +} /* namespace slh_dsa */ diff --git a/test.cpp b/test.cpp index 4d9d366..70e2e8d 100644 --- a/test.cpp +++ b/test.cpp @@ -12,8 +12,8 @@ static bool my_rand( void *target, size_t len ) { } int main(void) { - class sphincs_plus::key_sha256_192s_simple foo; -// class sphincs_plus::key_sha256_192f_simple foo; + class slh_dsa::key_sha2_192s foo; +// class slh_dsa::key_sha2_192f foo; // foo.set_num_thread(1); size_t len_pub_key = foo.len_public_key(); diff --git a/test_context.cpp b/test_context.cpp new file mode 100644 index 0000000..c0d34a9 --- /dev/null +++ b/test_context.cpp @@ -0,0 +1,148 @@ +#include +#include +#include +#include +#include "api.h" +#include "test_sphincs.h" + +// +// This tests out the context feature of SLH-DSA + +class context_test { + bool fast_flag; + enum noise_level level; +public: + context_test( bool flg, enum noise_level lev ) { + fast_flag = flg; + level = lev; + } + bool run( slh_dsa::key& k, const char *name, bool always ); +}; + +bool context_test::run( slh_dsa::key& k, + const char* parameter_set_name, bool always ) { + // If we're running in fast mode, skip any parameter set that is not + // marked as always + if (fast_flag && !always) return true; + + if (level == loud) { + printf( " Checking %s\n", parameter_set_name); + } + + // Create a parameter set + if (!k.generate_key_pair()) { + printf( "*** KEY GENERATION FAILED\n" ); + return false; + } + + bool hard_failure = false; + const int num_contexts = 6; // We current test 6 different contexts + // The first one is the default + struct context { + unsigned len; + char context[255]; + } contexts[num_contexts-1] = { + { 0, "" }, // Explicit NULL context + { 1, "A" }, // 1 character context + { 1, "B" }, // 1 character context + { 2, "AB" }, // 2 character context + { 2, "BA" }, // 2 character context + }; + unsigned char *sigs[num_contexts]; + + unsigned len_sig = k.len_signature(); + unsigned char message[] = "Hello spots fans"; + for (int i=0; i n) this_len = n; - sphincs_plus::sha512_update4x(&ctx_avx, b0+j, b1+j, b2+j, b3+j, this_len ); + slh_dsa::sha512_update4x(&ctx_avx, b0+j, b1+j, b2+j, b3+j, this_len ); } delete[] dummy_buf; __m256i out0[2], out1[2], out2[2], out3[2]; - sphincs_plus::sha512_final4x(&ctx_avx, out0, out1, out2, out3); + slh_dsa::sha512_final4x(&ctx_avx, out0, out1, out2, out3); void *out; switch (track) { case 0: out = out0; break; @@ -63,7 +63,7 @@ static bool test( const unsigned char *expected_result, } if (0 != memcmp( expected_result, out, - sphincs_plus::sha512_output_size )) { + slh_dsa::sha512_output_size )) { printf( " *** HASH MISMATCH track %d len %u n = %u\n", track, len_message, n ); return false; } diff --git a/test_sign.cpp b/test_sign.cpp index a56326a..7d98ef3 100644 --- a/test_sign.cpp +++ b/test_sign.cpp @@ -48,7 +48,7 @@ class sign_test { fast_flag = flg; level = lev; } - bool run( sphincs_plus::key& k, sphincs_plus::key& v, const char *name, bool always ); + bool run( slh_dsa::key& k, slh_dsa::key& v, const char *name, bool always ); }; // @@ -56,22 +56,22 @@ class sign_test { // interface to both // We also try it with the default opt_rand and having the caller // explicitly pass one in -static bool sign1( sphincs_plus::key& k, +static bool sign1( slh_dsa::key& k, const unsigned char *msg, size_t len_msg, unsigned char *sig_buffer) { return k.sign( sig_buffer, k.len_signature(), msg, len_msg ) && k.verify( sig_buffer, k.len_signature(), msg, len_msg ); } -static bool sign1( sphincs_plus::key& k, +static bool sign1( slh_dsa::key& k, const unsigned char *msg, size_t len_msg, unsigned char *sig_buffer, random_function rand ) { return k.sign( sig_buffer, k.len_signature(), - msg, len_msg, rand ) && + msg, len_msg, 0, 0, rand ) && k.verify( sig_buffer, k.len_signature(), msg, len_msg ); } -static bool sign2( sphincs_plus::key& k, +static bool sign2( slh_dsa::key& k, const unsigned char *msg, size_t len_msg, unsigned char *sig_buffer) { try { @@ -82,12 +82,12 @@ static bool sign2( sphincs_plus::key& k, return false; } } -static bool sign2( sphincs_plus::key& k, +static bool sign2( slh_dsa::key& k, const unsigned char *msg, size_t len_msg, unsigned char *sig_buffer, random_function rand ) { try { - auto sig = k.sign( msg, len_msg, rand ); + auto sig = k.sign( msg, len_msg, 0, 0, rand ); memcpy( sig_buffer, sig.get(), k.len_signature() ); return k.verify( sig_buffer, k.len_signature(), msg, len_msg ); } catch(std::exception& e) { @@ -95,7 +95,7 @@ static bool sign2( sphincs_plus::key& k, } } -bool sign_test::run( sphincs_plus::key& k, sphincs_plus::key& p, +bool sign_test::run( slh_dsa::key& k, slh_dsa::key& p, const char* parameter_set_name, bool always ) { // If we're running in fast mode, skip any parameter set that is not // marked as always @@ -227,7 +227,7 @@ bool sign_test::run( sphincs_plus::key& k, sphincs_plus::key& p, #define CONCAT( A, B ) A##B #define RUN_TEST(PARM_SET, always) { \ - CONCAT( sphincs_plus::key_, PARM_SET) k, k2; \ + CONCAT( slh_dsa::key_, PARM_SET) k, k2; \ if (!s.run( k, k2, #PARM_SET, always )) { \ return false; \ } \ @@ -240,46 +240,22 @@ bool test_sign(bool fast_flag, enum noise_level level) { // and selected 'S' parameter sets // L1 parameter sets - RUN_TEST( sha256_128s_simple, false ); - RUN_TEST( sha256_128f_simple, true ); - RUN_TEST( sha256_128s_robust, false ); - RUN_TEST( sha256_128f_robust, true ); - RUN_TEST( shake256_128s_simple, false ); - RUN_TEST( shake256_128f_simple, true ); - RUN_TEST( shake256_128s_robust, false ); - RUN_TEST( shake256_128f_robust, true ); - RUN_TEST( haraka_128s_simple, true ); - RUN_TEST( haraka_128f_simple, true ); - RUN_TEST( haraka_128s_robust, false ); - RUN_TEST( haraka_128f_robust, true ); + RUN_TEST( sha2_128s, false ); + RUN_TEST( sha2_128f, true ); + RUN_TEST( shake_128s, false ); + RUN_TEST( shake_128f, true ); // L3 parameter sets - RUN_TEST( sha256_192s_simple, false ); - RUN_TEST( sha256_192f_simple, true ); - RUN_TEST( sha256_192s_robust, false ); - RUN_TEST( sha256_192f_robust, true ); - RUN_TEST( shake256_192s_simple, false ); - RUN_TEST( shake256_192f_simple, true ); - RUN_TEST( shake256_192s_robust, false ); - RUN_TEST( shake256_192f_robust, true ); - RUN_TEST( haraka_192s_simple, false ); - RUN_TEST( haraka_192f_simple, true ); - RUN_TEST( haraka_192s_robust, false ); - RUN_TEST( haraka_192f_robust, true ); + RUN_TEST( sha2_192s, false ); + RUN_TEST( sha2_192f, true ); + RUN_TEST( shake_192s, false ); + RUN_TEST( shake_192f, true ); // L5 parameter sets - RUN_TEST( sha256_256s_simple, false ); - RUN_TEST( sha256_256f_simple, true ); - RUN_TEST( sha256_256s_robust, false ); - RUN_TEST( sha256_256f_robust, true ); - RUN_TEST( shake256_256s_simple, false ); - RUN_TEST( shake256_256f_simple, true ); - RUN_TEST( shake256_256s_robust, false ); - RUN_TEST( shake256_256f_robust, true ); - RUN_TEST( haraka_256s_simple, false ); - RUN_TEST( haraka_256f_simple, true ); - RUN_TEST( haraka_256s_robust, false ); - RUN_TEST( haraka_256f_robust, true ); + RUN_TEST( sha2_256s, false ); + RUN_TEST( sha2_256f, true ); + RUN_TEST( shake_256s, false ); + RUN_TEST( shake_256f, true ); return true; } diff --git a/test_sphincs.cpp b/test_sphincs.cpp index b9d50d6..c0eae4c 100644 --- a/test_sphincs.cpp +++ b/test_sphincs.cpp @@ -19,11 +19,13 @@ static struct { bool (*test_enabled)(bool); /* Check if this tests is enabled */ } test_list[] = { { "sha512", test_sha512, "internal SHA-512 implementation test", false, 0 }, - { "testvector", test_testvector, "test vectors extracted from the reference code", false, 0 }, + { "testkeygen", test_testvector_keygen, "keygen test vectors extracted from NIST", false, 0 }, + { "testsign", test_testvector_sign, "signature test vectors extracted from NIST", false, 0 }, { "keygen", test_keygen, "key generation test", false, 0 }, { "sign", test_sign, "signature generation test", false, 0 }, { "verify", test_verify, "signature verification test", true, 0 }, { "thread", test_thread, "threading test", false, 0 }, + { "context", test_context, "context test", false, 0 }, /* Add more here */ }; diff --git a/test_sphincs.h b/test_sphincs.h index 429bd6c..c94763b 100644 --- a/test_sphincs.h +++ b/test_sphincs.h @@ -2,11 +2,13 @@ #define TEST_SPHINCS_H_ enum noise_level { quiet, whisper, loud }; -extern bool test_testvector(bool fast_flag, enum noise_level level); +extern bool test_testvector_keygen(bool fast_flag, enum noise_level level); +extern bool test_testvector_sign(bool fast_flag, enum noise_level level); extern bool test_sha512(bool fast_flag, enum noise_level level); extern bool test_keygen(bool fast_flag, enum noise_level level); extern bool test_sign(bool fast_flag, enum noise_level level); extern bool test_verify(bool fast_flag, enum noise_level level); extern bool test_thread(bool fast_flag, enum noise_level level); +extern bool test_context(bool fast_flag, enum noise_level level); #endif /* TEST_SPHINCS_H_ */ diff --git a/test_testvector.cpp b/test_testvector.cpp deleted file mode 100644 index 434bc08..0000000 --- a/test_testvector.cpp +++ /dev/null @@ -1,233 +0,0 @@ -#include -#include -#include -#include "api.h" -#include "test_sphincs.h" - -// -// This tests out various test vectors from the reference code -// -// We are supposed to do the same transforms as the refence code; -// that is, the same seed -> private/public key and the same -// private key/optrand/message -> signature operation -// -// This tries to verify that both actually hold, by performing those -// operations with fixed inputs, and comparing them against what the -// reference code did with those same inputs (in the case of signatures, we -// hash the signatures, and compare hashes - there's no reason to include a -// 40k signature in our test files) -// -// For the public/private key generation, we use a fixed seed of -// the form 00 01 02 03 ... -// -// For signing, we use the optrand value specified in with the test -// vector -// -// Obvious question: why did we use an obviously nonrandom pattern -// for key generation, but a random one for signatures? The answer -// is what the reference code allowed to do (without changing that -// code); the refernce code gave us an API (crypto_sign_seed_keypair) -// that allowed us to specify the seed, so we picked a simple one. -// In constrast, the reference code always called randombytes() to -// get optrand (and didn't give us an option to skip it); however -// the infrastructure did allow us to switch to a determanistic -// version of randombytes(), so that's what we did - that version -// gave us a random-looking pattern, so that's what we got - -// -// Here is the set of test vectors extracted from the reference code -static struct v { - const char *parameter_set_name; // Name of the parameter set - unsigned char public_key[64]; // The public key that is generated with - // the fixed seed - unsigned char optrand[32]; // The optrand that was used when - // creating the signature - unsigned char hash_sig[32]; // The SHA256 hash of the signature of - // of the message "abc", using the given - // given optrand and generated private key -} vectors[] = { -#include "testvector.h" -}; - -class optrand_buffer : public sphincs_plus::random { - void *buffer; - size_t len; -public: - optrand_buffer( void *a, size_t b) : buffer(a), len(b) { ; } - virtual enum sphincs_plus::random_return operator()( void *target, - size_t num_bytes ) const { - if (num_bytes > len) return sphincs_plus::random_failure; - memcpy( target, buffer, num_bytes ); - return sphincs_plus::random_success; - } -}; - -// Given a parameter set name, return a key of that type -static sphincs_plus::key* lookup_key( const char *name) { - if (0 == strcmp( name, "sha2_128f_simple" )) - return new sphincs_plus::key_sha256_128f_simple; - if (0 == strcmp( name, "sha2_128f_robust" )) - return new sphincs_plus::key_sha256_128f_robust; - if (0 == strcmp( name, "shake_128f_simple" )) - return new sphincs_plus::key_shake256_128f_simple; - if (0 == strcmp( name, "shake_128f_robust" )) - return new sphincs_plus::key_shake256_128f_robust; - if (0 == strcmp( name, "haraka_128f_simple" )) - return new sphincs_plus::key_haraka_128f_simple; - if (0 == strcmp( name, "haraka_128f_robust" )) - return new sphincs_plus::key_haraka_128f_robust; - if (0 == strcmp( name, "sha2_128s_simple" )) - return new sphincs_plus::key_sha256_128s_simple; - if (0 == strcmp( name, "sha2_128s_robust" )) - return new sphincs_plus::key_sha256_128s_robust; - if (0 == strcmp( name, "shake_128s_simple" )) - return new sphincs_plus::key_shake256_128s_simple; - if (0 == strcmp( name, "shake_128s_robust" )) - return new sphincs_plus::key_shake256_128s_robust; - if (0 == strcmp( name, "haraka_128s_simple" )) - return new sphincs_plus::key_haraka_128s_simple; - if (0 == strcmp( name, "haraka_128s_robust" )) - return new sphincs_plus::key_haraka_128s_robust; - - if (0 == strcmp( name, "sha2_192f_simple" )) - return new sphincs_plus::key_sha256_192f_simple; - if (0 == strcmp( name, "sha2_192f_robust" )) - return new sphincs_plus::key_sha256_192f_robust; - if (0 == strcmp( name, "shake_192f_simple" )) - return new sphincs_plus::key_shake256_192f_simple; - if (0 == strcmp( name, "shake_192f_robust" )) - return new sphincs_plus::key_shake256_192f_robust; - if (0 == strcmp( name, "haraka_192f_simple" )) - return new sphincs_plus::key_haraka_192f_simple; - if (0 == strcmp( name, "haraka_192f_robust" )) - return new sphincs_plus::key_haraka_192f_robust; - if (0 == strcmp( name, "sha2_192s_simple" )) - return new sphincs_plus::key_sha256_192s_simple; - if (0 == strcmp( name, "sha2_192s_robust" )) - return new sphincs_plus::key_sha256_192s_robust; - if (0 == strcmp( name, "shake_192s_simple" )) - return new sphincs_plus::key_shake256_192s_simple; - if (0 == strcmp( name, "shake_192s_robust" )) - return new sphincs_plus::key_shake256_192s_robust; - if (0 == strcmp( name, "haraka_192s_simple" )) - return new sphincs_plus::key_haraka_192s_simple; - if (0 == strcmp( name, "haraka_192s_robust" )) - return new sphincs_plus::key_haraka_192s_robust; - - if (0 == strcmp( name, "sha2_256f_simple" )) - return new sphincs_plus::key_sha256_256f_simple; - if (0 == strcmp( name, "sha2_256f_robust" )) - return new sphincs_plus::key_sha256_256f_robust; - if (0 == strcmp( name, "shake_256f_simple" )) - return new sphincs_plus::key_shake256_256f_simple; - if (0 == strcmp( name, "shake_256f_robust" )) - return new sphincs_plus::key_shake256_256f_robust; - if (0 == strcmp( name, "haraka_256f_simple" )) - return new sphincs_plus::key_haraka_256f_simple; - if (0 == strcmp( name, "haraka_256f_robust" )) - return new sphincs_plus::key_haraka_256f_robust; - if (0 == strcmp( name, "sha2_256s_simple" )) - return new sphincs_plus::key_sha256_256s_simple; - if (0 == strcmp( name, "sha2_256s_robust" )) - return new sphincs_plus::key_sha256_256s_robust; - if (0 == strcmp( name, "shake_256s_simple" )) - return new sphincs_plus::key_shake256_256s_simple; - if (0 == strcmp( name, "shake_256s_robust" )) - return new sphincs_plus::key_shake256_256s_robust; - if (0 == strcmp( name, "haraka_256s_simple" )) - return new sphincs_plus::key_haraka_256s_simple; - if (0 == strcmp( name, "haraka_256s_robust" )) - return new sphincs_plus::key_haraka_256s_robust; - - printf( "*** UNRECOGNIZED PARAMETER SET %s\n", name ); - return 0; -} - -// -// This is an 'RNG' that gives the fixed pattern that our -// test vectors expect on keygen -static bool fixed_rand( void *target, size_t num_bytes ) { - unsigned char *p = (unsigned char *)target; - for (unsigned i=0; igenerate_key_pair(fixed_rand)) { - delete k; - printf( "*** ERROR GENERATING KEY\n" ); - return 0; - } - - // Check if it got the public key we expect - if (0 != memcmp( v.public_key, k->get_public_key(), - k->len_public_key() )) { - delete k; - printf( "*** GENERATING DIFFERENT PUBLIC KEY FOR %s\n", - v.parameter_set_name ); - return 0; - } - - // That passed; now on to the signature - optrand_buffer optrand( v.optrand, 32 ); - - static unsigned char message[3] = { 'a', 'b', 'c' }; - unsigned char* sig = new unsigned char[k->len_signature()]; - - // And sign the message - if (!k->sign( sig, k->len_signature(), message, sizeof message, - optrand )) { - delete[] sig; - delete k; - printf( "*** ERROR GENERATING SIGNATURE\n" ); - return 0; - } - - // Hash the signature - unsigned char hash[32]; - sha256( hash, sig, k->len_signature() ); - - delete[] sig; // We're done with these - delete k; - - // Check if we got the expeccted hash - if (0 != memcmp( v.hash_sig, hash, 32 )) { - printf( "*** GENERATING DIFFERENT SGNATURES FOR %s\n", - v.parameter_set_name ); - return 0; - } - - // We're good for this parameter set - } - - return 1; -} diff --git a/test_testvector_keygen.cpp b/test_testvector_keygen.cpp new file mode 100644 index 0000000..9d003c0 --- /dev/null +++ b/test_testvector_keygen.cpp @@ -0,0 +1,133 @@ +#include +#include +#include +#include "api.h" +#include "test_sphincs.h" + +// +// This tests out various test vectors published by NIST +// +// We are supposed to do the same transforms as what NIST requires +// that is, the same seed -> private/public key and the same +// private key/optrand/message -> signature operation +// +// This tries to verify that first one, by performing keygen with fixed inputs, +// and comparing the results against what the published NIST test vectors say +// + +// +// Here is the set of test vectors extracted from the reference code +static struct w { + const char *parameter_set_name; // Name of the parameter set + unsigned seed_len; + const char *seed; // The seed + unsigned public_key_len; + const char *public_key; // The expected public key + unsigned private_key_len; + const char *private_key; // The expected private key +} vectors[] = { +#include "testvector_keygen.h" +}; + +// +class seed_buffer : public slh_dsa::random { + const void *buffer; + size_t len; +public: + seed_buffer( const void *a, size_t b) : buffer(a), len(b) { ; } + virtual enum slh_dsa::random_return operator()( void *target, + size_t num_bytes ) const { + if (num_bytes > len) return slh_dsa::random_failure; + memcpy( target, buffer, num_bytes ); + return slh_dsa::random_success; + } +}; + +// Given a parameter set name, return a key of that type +static slh_dsa::key* lookup_key( const char *name) { + if (0 == strcmp( name, "SLH-DSA-SHA2-128f" )) + return new slh_dsa::key_sha2_128f; + if (0 == strcmp( name, "SLH-DSA-SHAKE-128f" )) + return new slh_dsa::key_shake_128f; + if (0 == strcmp( name, "SLH-DSA-SHA2-128s" )) + return new slh_dsa::key_sha2_128s; + if (0 == strcmp( name, "SLH-DSA-SHAKE-128s" )) + return new slh_dsa::key_shake_128s; + + if (0 == strcmp( name, "SLH-DSA-SHA2-192f" )) + return new slh_dsa::key_sha2_192f; + if (0 == strcmp( name, "SLH-DSA-SHAKE-192f" )) + return new slh_dsa::key_shake_192f; + if (0 == strcmp( name, "SLH-DSA-SHA2-192s" )) + return new slh_dsa::key_sha2_192s; + if (0 == strcmp( name, "SLH-DSA-SHAKE-192s" )) + return new slh_dsa::key_shake_192s; + + if (0 == strcmp( name, "SLH-DSA-SHA2-256f" )) + return new slh_dsa::key_sha2_256f; + if (0 == strcmp( name, "SLH-DSA-SHAKE-256f" )) + return new slh_dsa::key_shake_256f; + if (0 == strcmp( name, "SLH-DSA-SHA2-256s" )) + return new slh_dsa::key_sha2_256s; + if (0 == strcmp( name, "SLH-DSA-SHAKE-256s" )) + return new slh_dsa::key_shake_256s; + + printf( "*** UNRECOGNIZED PARAMETER SET %s\n", name ); + return 0; +} + +// +// And here is the main code which actually runs the test +bool test_testvector_keygen(bool fast_flag, enum noise_level level) { + + const char *last_test = 0; + + for (unsigned i=0; i(v.seed), + v.seed_len ); + + // And generate the public/private keypair + slh_dsa::success_flag s = k->generate_key_pair(seed); + if (s != slh_dsa::success) { + printf( "FAILURE IN KEY GENERATION\n" ); + return false; + } + + // Check if the public key is what we expect + const unsigned char *key; + key = k->get_public_key(); + if (!key || 0 != memcmp( key, v.public_key, v.public_key_len )) { + printf( "INCORRECT PUBLIC KEY\n" ); + } + + // Check if the private key is what we expect + key = k->get_private_key(); + if (!key || 0 != memcmp( key, v.private_key, v.private_key_len )) { + printf( "INCORRECT PRIVATE KEY\n" ); + } + + // We're good for this parameter set + } + + return 1; +} diff --git a/test_testvector_sign.cpp b/test_testvector_sign.cpp new file mode 100644 index 0000000..e4f68b8 --- /dev/null +++ b/test_testvector_sign.cpp @@ -0,0 +1,190 @@ +#include +#include +#include +#include "api.h" +#include "test_sphincs.h" + +// +// This tests out various test vectors published by NIST +// +// We are supposed to do the same transforms as what NIST requires +// that is, the same seed -> private/public key and the same +// private key/optrand/message -> signature operation +// +// This tries to verify the second, by performing those operations with fixed +// inputs, and comparing them against what the NIST test vectors had. +// For signatures, we hash them and compare hashes - there's no reason to +// include a +// 40k signature in our test files) +// + +// +// Here is the set of test vectors extracted from the reference code +static struct v { + const char *parameter_set_name; // Name of the parameter set + const char *optrand; // Optrand - NULL for determinstic + const char *priv_key; // The private key + unsigned context_len; // The length of the context + const char *context; // The context + slh_dsa::hash_type *prehash; // The prehash to use + // NULL for pure + unsigned message_len; // The message length + const char *message; // The message (or the hash message if + // we're testing prehash) + unsigned char hash_sig[32]; // The SHA256 hash of the signature +} vectors[] = { +#include "testvector_sign.h" +}; + +// +// This class is here because the compiler insists on a virtual destructor +class our_random : public slh_dsa::random { +public: + virtual ~our_random(void) { ; } +}; + +class optrand_buffer : public our_random { + const void *buffer; + size_t len; +public: + optrand_buffer( const void *a, size_t b) : buffer(a), len(b) { ; } + virtual enum slh_dsa::random_return operator()( void *target, + size_t num_bytes ) const { + if (num_bytes > len) return slh_dsa::random_failure; + memcpy( target, buffer, num_bytes ); + return slh_dsa::random_success; + } +}; + +class optrand_default : public our_random { +public: + virtual enum slh_dsa::random_return operator()( void *target, + size_t num_bytes ) const { + (void)target; /* STUPID COMPILER */ + (void)num_bytes; + return slh_dsa::random_default; + } +}; + +// Given a parameter set name, return a key of that type +static slh_dsa::key* lookup_key( const char *name) { + if (0 == strcmp( name, "SLH-DSA-SHA2-128f" )) + return new slh_dsa::key_sha2_128f; + if (0 == strcmp( name, "SLH-DSA-SHAKE-128f" )) + return new slh_dsa::key_shake_128f; + if (0 == strcmp( name, "SLH-DSA-SHA2-128s" )) + return new slh_dsa::key_sha2_128s; + if (0 == strcmp( name, "SLH-DSA-SHAKE-128s" )) + return new slh_dsa::key_shake_128s; + + if (0 == strcmp( name, "SLH-DSA-SHA2-192f" )) + return new slh_dsa::key_sha2_192f; + if (0 == strcmp( name, "SLH-DSA-SHAKE-192f" )) + return new slh_dsa::key_shake_192f; + if (0 == strcmp( name, "SLH-DSA-SHA2-192s" )) + return new slh_dsa::key_sha2_192s; + if (0 == strcmp( name, "SLH-DSA-SHAKE-192s" )) + return new slh_dsa::key_shake_192s; + + if (0 == strcmp( name, "SLH-DSA-SHA2-256f" )) + return new slh_dsa::key_sha2_256f; + if (0 == strcmp( name, "SLH-DSA-SHAKE-256f" )) + return new slh_dsa::key_shake_256f; + if (0 == strcmp( name, "SLH-DSA-SHA2-256s" )) + return new slh_dsa::key_sha2_256s; + if (0 == strcmp( name, "SLH-DSA-SHAKE-256s" )) + return new slh_dsa::key_shake_256s; + + printf( "*** UNRECOGNIZED PARAMETER SET %s\n", name ); + return 0; +} + +// For our SHA256 implementation, we borrow the one from Sphincs +#include "sha256.h" +static void sha256( unsigned char *output, + const unsigned char *input, size_t len ) { + slh_dsa::SHA256_CTX ctx; + ctx.init(); + ctx.update(input, len); + ctx.final(output); +} + + +// +// And here is the main code which actually runs the test +bool test_testvector_sign(bool fast_flag, enum noise_level level) { + bool did_prehash = false; + bool did_deterministic = false; + + for (unsigned i=0; iset_private_key( reinterpret_cast(v.priv_key) ); + + // Generate the signature + our_random *optrand = 0; + if (v.optrand) { + optrand = new optrand_buffer( v.optrand, 32 ); + } else { + optrand = new optrand_default; + did_deterministic = true; // Don't forget + } + + const unsigned char *message = reinterpret_cast(v.message); + unsigned char* sig = new unsigned char[k->len_signature()]; + + // And sign the message + slh_dsa::success_flag s; + const unsigned char *context = reinterpret_cast(v.context); + if (v.prehash) { + // Prehash API + s = k->sign( sig, k->len_signature(), message, v.message_len, + *v.prehash, context, v.context_len, *optrand ); + + did_prehash = true; // Don't forget + } else { + // Pure API + s = k->sign( sig, k->len_signature(), message, v.message_len, + context, v.context_len, *optrand ); + } + if (s != slh_dsa::success) { + delete[] sig; + delete k; + delete optrand; + printf( "*** ERROR GENERATING SIGNATURE\n" ); + return 0; + } + + // Hash the signature + unsigned char hash[32]; + sha256( hash, sig, k->len_signature() ); + + delete[] sig; // We're done with these + delete k; + delete optrand; + + // Check if we got the expeccted hash + if (0 != memcmp( v.hash_sig, hash, 32 )) { + printf( "*** GENERATING DIFFERENT SGNATURES FOR %s\n", + v.parameter_set_name ); + return 0; + } + + // We're good for this parameter set + } + + return 1; +} diff --git a/test_thread.cpp b/test_thread.cpp index 3ad105f..6db2ce5 100644 --- a/test_thread.cpp +++ b/test_thread.cpp @@ -16,19 +16,19 @@ class thread_test { fast_flag = flg; level = lev; } - bool run( sphincs_plus::key& k, const char *name, bool always ); + bool run( slh_dsa::key& k, const char *name, bool always ); }; // We need to generate the signatures in determanistic mode -static bool sign( sphincs_plus::key& k, +static bool sign( slh_dsa::key& k, const unsigned char *msg, size_t len_msg, unsigned char *sig_buffer) { return k.sign( sig_buffer, k.len_signature(), - msg, len_msg, 0 ) && + msg, len_msg, 0, 0, 0 ) && k.verify( sig_buffer, k.len_signature(), msg, len_msg ); } -bool thread_test::run( sphincs_plus::key& k, +bool thread_test::run( slh_dsa::key& k, const char* parameter_set_name, bool always ) { // If we're running in fast mode, skip any parameter set that is not // marked as always @@ -80,7 +80,7 @@ bool thread_test::run( sphincs_plus::key& k, #define CONCAT( A, B ) A##B #define RUN_TEST(PARM_SET, always) { \ - CONCAT( sphincs_plus::key_, PARM_SET) k; \ + CONCAT( slh_dsa::key_, PARM_SET) k; \ if (!s.run( k, #PARM_SET, always )) { \ return false; \ } \ @@ -93,46 +93,22 @@ bool test_thread(bool fast_flag, enum noise_level level) { // and selected 'S' parameter sets // L1 parameter sets - RUN_TEST( sha256_128s_simple, true ); - RUN_TEST( sha256_128f_simple, true ); - RUN_TEST( sha256_128s_robust, false ); - RUN_TEST( sha256_128f_robust, true ); - RUN_TEST( shake256_128s_simple, false ); - RUN_TEST( shake256_128f_simple, true ); - RUN_TEST( shake256_128s_robust, false ); - RUN_TEST( shake256_128f_robust, true ); - RUN_TEST( haraka_128s_simple, false ); - RUN_TEST( haraka_128f_simple, true ); - RUN_TEST( haraka_128s_robust, true ); - RUN_TEST( haraka_128f_robust, true ); + RUN_TEST( sha2_128s, true ); + RUN_TEST( sha2_128f, true ); + RUN_TEST( shake_128s, false ); + RUN_TEST( shake_128f, true ); // L3 parameter sets - RUN_TEST( sha256_192s_simple, false ); - RUN_TEST( sha256_192f_simple, true ); - RUN_TEST( sha256_192s_robust, false ); - RUN_TEST( sha256_192f_robust, true ); - RUN_TEST( shake256_192s_simple, false ); - RUN_TEST( shake256_192f_simple, true ); - RUN_TEST( shake256_192s_robust, false ); - RUN_TEST( shake256_192f_robust, true ); - RUN_TEST( haraka_192s_simple, true ); - RUN_TEST( haraka_192f_simple, true ); - RUN_TEST( haraka_192s_robust, false ); - RUN_TEST( haraka_192f_robust, true ); + RUN_TEST( sha2_192s, false ); + RUN_TEST( sha2_192f, true ); + RUN_TEST( shake_192s, false ); + RUN_TEST( shake_192f, true ); // L5 parameter sets - RUN_TEST( sha256_256s_simple, false ); - RUN_TEST( sha256_256f_simple, true ); - RUN_TEST( sha256_256s_robust, false ); - RUN_TEST( sha256_256f_robust, true ); - RUN_TEST( shake256_256s_simple, false ); - RUN_TEST( shake256_256f_simple, true ); - RUN_TEST( shake256_256s_robust, false ); - RUN_TEST( shake256_256f_robust, true ); - RUN_TEST( haraka_256s_simple, true ); - RUN_TEST( haraka_256f_simple, true ); - RUN_TEST( haraka_256s_robust, false ); - RUN_TEST( haraka_256f_robust, true ); + RUN_TEST( sha2_256s, false ); + RUN_TEST( sha2_256f, true ); + RUN_TEST( shake_256s, false ); + RUN_TEST( shake_256f, true ); return true; } diff --git a/test_verify.cpp b/test_verify.cpp index 0f17bd9..650b0ab 100644 --- a/test_verify.cpp +++ b/test_verify.cpp @@ -19,14 +19,14 @@ class verify_test { prev_percentage = -1; } void set_iter(unsigned it) { iter = it; } - bool run( sphincs_plus::key& k, sphincs_plus::key& v, const char *name, bool always ); + bool run( slh_dsa::key& k, slh_dsa::key& v, const char *name, bool always ); }; // // The first key is what we use to generate the signature // The second key is what we use to verify the signature; it is not given a copy // of the private key -bool verify_test::run( sphincs_plus::key& k, sphincs_plus::key& v, +bool verify_test::run( slh_dsa::key& k, slh_dsa::key& v, const char* parameter_set_name, bool always ) { // If we're running in fast mode, skip any parameter set that is not // marked as always @@ -128,7 +128,7 @@ bool verify_test::run( sphincs_plus::key& k, sphincs_plus::key& v, #define CONCAT( A, B ) A##B #define RUN_TEST(PARM_SET, always) { \ - CONCAT( sphincs_plus::key_, PARM_SET) k, k2; \ + CONCAT( slh_dsa::key_, PARM_SET) k, k2; \ if (!v.run( k, k2, #PARM_SET, always )) { \ return false; \ } \ @@ -147,46 +147,22 @@ bool test_verify(bool fast_flag, enum noise_level level) { */ // L1 parameter sets - RUN_TEST( sha256_128s_simple, true ); - RUN_TEST( sha256_128f_simple, false ); - RUN_TEST( sha256_128s_robust, true ); - RUN_TEST( sha256_128f_robust, false ); - RUN_TEST( shake256_128s_simple, true ); - RUN_TEST( shake256_128f_simple, false ); - RUN_TEST( shake256_128s_robust, false ); - RUN_TEST( shake256_128f_robust, false ); - RUN_TEST( haraka_128s_simple, false ); - RUN_TEST( haraka_128f_simple, true ); - RUN_TEST( haraka_128s_robust, true ); - RUN_TEST( haraka_128f_robust, false ); + RUN_TEST( sha2_128s, true ); + RUN_TEST( sha2_128f, false ); + RUN_TEST( shake_128s, true ); + RUN_TEST( shake_128f, false ); // L3 parameter sets - RUN_TEST( sha256_192s_simple, true ); - RUN_TEST( sha256_192f_simple, false ); - RUN_TEST( sha256_192s_robust, false ); - RUN_TEST( sha256_192f_robust, false ); - RUN_TEST( shake256_192s_simple, false ); - RUN_TEST( shake256_192f_simple, false ); - RUN_TEST( shake256_192s_robust, false ); - RUN_TEST( shake256_192f_robust, false ); - RUN_TEST( haraka_192s_simple, true ); - RUN_TEST( haraka_192f_simple, false ); - RUN_TEST( haraka_192s_robust, false ); - RUN_TEST( haraka_192f_robust, false ); + RUN_TEST( sha2_192s, true ); + RUN_TEST( sha2_192f, false ); + RUN_TEST( shake_192s, false ); + RUN_TEST( shake_192f, false ); // L5 parameter sets - RUN_TEST( sha256_256s_simple, true ); - RUN_TEST( sha256_256f_simple, false ); - RUN_TEST( sha256_256s_robust, false ); - RUN_TEST( sha256_256f_robust, false ); - RUN_TEST( shake256_256s_simple, false ); - RUN_TEST( shake256_256f_simple, false ); - RUN_TEST( shake256_256s_robust, false ); - RUN_TEST( shake256_256f_robust, false ); - RUN_TEST( haraka_256s_simple, true ); - RUN_TEST( haraka_256f_simple, false ); - RUN_TEST( haraka_256s_robust, false ); - RUN_TEST( haraka_256f_robust, false ); + RUN_TEST( sha2_256s, true ); + RUN_TEST( sha2_256f, false ); + RUN_TEST( shake_256s, false ); + RUN_TEST( shake_256f, false ); } return true; diff --git a/testvector.h b/testvector.h deleted file mode 100644 index 21b2707..0000000 --- a/testvector.h +++ /dev/null @@ -1,578 +0,0 @@ -/* This is a computer generated file */ -/* Do not edit this directly */ -{ - "shake_128f_robust", - { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - 0x1b, 0x59, 0x6e, 0xa4, 0x93, 0xac, 0x9f, 0x74, - 0x8c, 0x00, 0x82, 0x7b, 0x0c, 0x8b, 0xce, 0xbd, }, - { 0xc6, 0xb5, 0x6c, 0xc5, 0x46, 0x66, 0x3d, 0x20, - 0xfd, 0xd8, 0x3a, 0xf9, 0x20, 0x62, 0x32, 0x16, }, - { 0x50, 0xe6, 0x11, 0x1b, 0x92, 0xb9, 0x2a, 0x39, - 0x80, 0xd5, 0x9d, 0x69, 0x56, 0x9c, 0xff, 0xa3, - 0x83, 0x88, 0x06, 0x7c, 0x8d, 0x70, 0xd6, 0xc1, - 0x85, 0x2e, 0x19, 0x6e, 0xf4, 0xed, 0x26, 0x89, }, -}, -{ - "shake_128f_simple", - { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - 0xa9, 0x0e, 0x47, 0x15, 0xb9, 0xa9, 0x25, 0xc3, - 0x32, 0x80, 0x17, 0x67, 0xfd, 0x78, 0x63, 0x71, }, - { 0x9e, 0x59, 0x80, 0xe2, 0x0c, 0x0c, 0x1f, 0xc0, - 0x2c, 0x7c, 0xf9, 0x47, 0xe8, 0xb6, 0x61, 0xb1, }, - { 0x13, 0x5e, 0x4b, 0xce, 0x56, 0x48, 0x4c, 0x13, - 0x9a, 0xbc, 0x40, 0x60, 0x8f, 0xba, 0x00, 0x94, - 0xb2, 0xb2, 0x7d, 0x6a, 0x5b, 0xe6, 0xc7, 0x4f, - 0x40, 0x7f, 0x60, 0x8a, 0xf5, 0xb1, 0x06, 0xd4, }, -}, -{ - "shake_192f_robust", - { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x91, 0x92, 0x23, 0x80, 0x12, 0x48, 0xff, 0x42, - 0x0b, 0xb3, 0x26, 0x28, 0xa7, 0x92, 0x0e, 0xcc, - 0x73, 0x10, 0x26, 0xe0, 0xf7, 0x09, 0x6d, 0xbd, }, - { 0x00, 0x34, 0xf8, 0x23, 0xf1, 0x3f, 0xde, 0x06, - 0x5c, 0x2a, 0x61, 0x7d, 0x15, 0x50, 0xd6, 0x7f, - 0x05, 0x56, 0x6f, 0xa5, 0x71, 0xc2, 0x25, 0xb7, }, - { 0x09, 0xf0, 0x3a, 0x1d, 0x49, 0xd9, 0xb7, 0x40, - 0xf5, 0xd9, 0xbb, 0x2d, 0xab, 0xcc, 0x50, 0xf0, - 0xe8, 0xe4, 0x87, 0x7c, 0x7d, 0xfe, 0xcf, 0xc0, - 0x44, 0xf7, 0x54, 0x0c, 0xd9, 0x3c, 0x5c, 0x05, }, -}, -{ - "shake_192f_simple", - { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x3f, 0x01, 0xb0, 0x6b, 0xeb, 0xed, 0x02, 0x0a, - 0x45, 0x96, 0x96, 0x86, 0x8d, 0x11, 0x5f, 0xe8, - 0x50, 0x7d, 0xed, 0x8d, 0xc0, 0x8e, 0x82, 0x5d, }, - { 0x88, 0x41, 0x23, 0x4e, 0x70, 0xc3, 0x1b, 0x44, - 0x27, 0x36, 0xfd, 0x5a, 0x9b, 0x6c, 0x2b, 0x7b, - 0x01, 0x30, 0x73, 0xf6, 0x83, 0x9e, 0x7b, 0xb6, }, - { 0x6f, 0x5b, 0x6d, 0x9f, 0x6c, 0x11, 0x1a, 0x10, - 0x6e, 0xa6, 0x1a, 0x71, 0x37, 0xa2, 0x35, 0xf8, - 0xac, 0x54, 0x76, 0x22, 0x11, 0x99, 0x0c, 0x3f, - 0x35, 0x02, 0xda, 0x17, 0x74, 0x5b, 0x4b, 0xf5, }, -}, -{ - "shake_256f_robust", - { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, - 0xb9, 0x3c, 0xcd, 0xac, 0x91, 0x11, 0x51, 0x66, - 0xb8, 0x38, 0x19, 0x99, 0x22, 0x40, 0xf9, 0xeb, - 0x70, 0x53, 0xe9, 0x06, 0x64, 0x54, 0x02, 0x18, - 0xdd, 0xcb, 0x50, 0x66, 0x73, 0x93, 0x26, 0xfa, }, - { 0xfc, 0x8d, 0x27, 0xed, 0x0d, 0x2a, 0x7e, 0xc5, - 0xb9, 0x7d, 0xd5, 0x2f, 0x86, 0x72, 0x7f, 0x69, - 0x70, 0xa3, 0x1e, 0xc4, 0x21, 0x7e, 0xd5, 0x37, - 0x49, 0x9e, 0x76, 0x10, 0xce, 0xca, 0x4d, 0x21, }, - { 0x7f, 0x3e, 0xee, 0x87, 0x49, 0x9b, 0xa6, 0x24, - 0xe6, 0x74, 0x00, 0x56, 0x67, 0x70, 0xe0, 0x9e, - 0x2b, 0xbe, 0xc5, 0xd5, 0xb3, 0xeb, 0x87, 0x61, - 0xc1, 0x23, 0xf9, 0x87, 0xbd, 0xed, 0x3e, 0x28, }, -}, -{ - "shake_256f_simple", - { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, - 0x81, 0x8d, 0x7e, 0x76, 0xbe, 0xef, 0x97, 0x9b, - 0x5b, 0xbf, 0x91, 0x61, 0xfd, 0xef, 0xa2, 0x1b, - 0xd0, 0xfe, 0x0b, 0xfe, 0x19, 0x15, 0x7a, 0x57, - 0x11, 0xa8, 0xde, 0x8a, 0x8f, 0x68, 0x78, 0xe6, }, - { 0x5e, 0xe7, 0x92, 0x0f, 0x5e, 0xbc, 0x5c, 0xbb, - 0x0c, 0xa6, 0xd0, 0x66, 0x80, 0x42, 0x66, 0xc8, - 0x9d, 0x30, 0x14, 0xbc, 0xe1, 0x09, 0x56, 0x0d, - 0x3e, 0xe6, 0x55, 0xf2, 0x1d, 0x80, 0x94, 0x01, }, - { 0x53, 0xd6, 0x3d, 0xda, 0x8e, 0x88, 0xc6, 0x40, - 0x8c, 0xc0, 0x13, 0x0e, 0xc1, 0xab, 0x3c, 0x98, - 0x0c, 0x26, 0x0d, 0x90, 0x24, 0x4e, 0x92, 0x56, - 0x50, 0x20, 0xbc, 0x67, 0x7d, 0xdd, 0xd6, 0x7a, }, -}, -{ - "shake_128s_robust", - { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - 0xda, 0x79, 0xbd, 0xe3, 0xca, 0xe0, 0xf6, 0x63, - 0xec, 0x5c, 0x82, 0x48, 0xeb, 0xad, 0x07, 0xf2, }, - { 0x85, 0xf3, 0x54, 0x32, 0xad, 0xe4, 0xae, 0x56, - 0x85, 0x0e, 0x9e, 0xe0, 0xaf, 0x6e, 0x70, 0x40, }, - { 0xb4, 0xb2, 0xc4, 0x1c, 0x97, 0xb3, 0x37, 0x5f, - 0xf6, 0xd9, 0xc8, 0xf5, 0x31, 0xf5, 0xa8, 0xbc, - 0x1e, 0x3f, 0x6b, 0x89, 0x67, 0x8e, 0x55, 0xb5, - 0x05, 0xce, 0xd9, 0x55, 0x3d, 0x1e, 0xb5, 0x3f, }, -}, -{ - "shake_128s_simple", - { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - 0x89, 0xfd, 0x81, 0xfd, 0xbb, 0x5b, 0x94, 0x12, - 0x9b, 0x14, 0x76, 0x1b, 0xdc, 0x6b, 0xf6, 0x82, }, - { 0x1d, 0xc2, 0x1e, 0xee, 0xcb, 0x54, 0xd3, 0xda, - 0x90, 0xb8, 0x26, 0x41, 0x35, 0xb2, 0x2d, 0xda, }, - { 0x1c, 0x2a, 0x10, 0xe7, 0x74, 0xe5, 0xdd, 0x44, - 0x8a, 0x19, 0xbf, 0xd8, 0x1f, 0xeb, 0x35, 0xe7, - 0x10, 0x8b, 0x19, 0x92, 0xf7, 0x04, 0x4c, 0x35, - 0x28, 0x7e, 0xd7, 0x3c, 0xce, 0xf3, 0xb2, 0x5e, }, -}, -{ - "shake_192s_robust", - { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x15, 0x6a, 0x6f, 0x30, 0x10, 0x0d, 0x61, 0xe7, - 0xc1, 0x23, 0xea, 0x11, 0x46, 0x03, 0x05, 0x38, - 0x6e, 0xd7, 0x4f, 0x7d, 0x26, 0x90, 0x2f, 0xec, }, - { 0xb5, 0x1f, 0xd7, 0x07, 0xbd, 0x28, 0x95, 0xb4, - 0x84, 0x97, 0x32, 0x3d, 0xf6, 0x3e, 0xd6, 0x4f, - 0xda, 0x13, 0x2c, 0xf2, 0x0f, 0xc6, 0x30, 0x99, }, - { 0x13, 0x34, 0x5d, 0x6f, 0x87, 0xe3, 0x77, 0x61, - 0x53, 0x36, 0x7c, 0x4e, 0x0d, 0xe9, 0x85, 0xb8, - 0x17, 0x3a, 0x75, 0xc8, 0xd1, 0x49, 0x6f, 0x25, - 0x65, 0x6e, 0x63, 0x72, 0x48, 0xba, 0x0f, 0xf7, }, -}, -{ - "shake_192s_simple", - { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0xeb, 0x24, 0x7f, 0x95, 0x5d, 0x8e, 0xca, 0x24, - 0xa5, 0x86, 0x05, 0x36, 0xc5, 0x6b, 0x2c, 0x4d, - 0x1e, 0x8d, 0x8e, 0x83, 0x5e, 0xb2, 0x7d, 0x2d, }, - { 0x88, 0xc0, 0x68, 0x73, 0x46, 0xda, 0xe0, 0xc3, - 0x3d, 0x12, 0x45, 0x65, 0x49, 0x62, 0xaf, 0x2f, - 0x45, 0x57, 0x1a, 0x51, 0x0c, 0x7a, 0x32, 0xc4, }, - { 0x62, 0xe8, 0x56, 0xa3, 0x50, 0x1d, 0xec, 0x02, - 0x43, 0xe2, 0x4e, 0xdd, 0x6b, 0x9b, 0xe0, 0x6b, - 0x50, 0x5f, 0x47, 0x24, 0x2d, 0xe6, 0x15, 0x16, - 0x2c, 0xf7, 0x34, 0xa7, 0xaa, 0xf0, 0xc4, 0xb5, }, -}, -{ - "shake_256s_robust", - { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, - 0xd4, 0x36, 0x91, 0xb1, 0x1d, 0xe1, 0x68, 0x28, - 0x72, 0xca, 0x3b, 0x27, 0x0b, 0x4e, 0x23, 0x99, - 0x21, 0x18, 0x69, 0x3a, 0x31, 0x1b, 0xd6, 0xd9, - 0x4b, 0xa8, 0xc7, 0xa2, 0xbb, 0x1e, 0xf1, 0x2b, }, - { 0x73, 0xd1, 0xa9, 0x67, 0x47, 0x73, 0x87, 0x80, - 0x2e, 0xd0, 0x02, 0x2c, 0xba, 0x0c, 0xf2, 0x74, - 0x35, 0x7a, 0x52, 0xf9, 0x16, 0x8b, 0x64, 0x4f, - 0xd1, 0x20, 0xeb, 0xfc, 0x8c, 0xb8, 0xa6, 0x73, }, - { 0x05, 0x5e, 0xaf, 0x79, 0x55, 0x3a, 0x57, 0x7c, - 0x1e, 0x75, 0xae, 0xcd, 0x85, 0x62, 0x4b, 0xe2, - 0x4b, 0x1c, 0xc5, 0x1d, 0x12, 0xcc, 0x5e, 0x15, - 0xff, 0x2c, 0xd2, 0xe3, 0x11, 0xc9, 0x04, 0x5b, }, -}, -{ - "shake_256s_simple", - { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, - 0x27, 0xea, 0x44, 0x4d, 0xbc, 0x8c, 0xa9, 0xc1, - 0x69, 0xfd, 0x48, 0x4b, 0x9e, 0x97, 0x7e, 0xb7, - 0x7a, 0x4f, 0x23, 0x35, 0x50, 0x75, 0x7e, 0x02, - 0x5c, 0xf1, 0x80, 0xed, 0xe7, 0xe8, 0x83, 0x9f, }, - { 0x43, 0xb0, 0x57, 0x64, 0x5c, 0xaf, 0xa9, 0xe2, - 0x90, 0x49, 0xf6, 0xc8, 0x76, 0x25, 0xb9, 0xb9, - 0x9d, 0x49, 0x53, 0x67, 0xff, 0x5d, 0xc0, 0x4d, - 0x5e, 0x94, 0x05, 0xc3, 0x86, 0xc3, 0xc8, 0x59, }, - { 0x54, 0x44, 0xa9, 0x87, 0x61, 0x6c, 0x1b, 0xd3, - 0xde, 0x27, 0x2a, 0xe0, 0x93, 0xb3, 0x3f, 0x5b, - 0x00, 0xb3, 0x58, 0x8c, 0x47, 0x70, 0x05, 0x07, - 0xd9, 0xf8, 0x84, 0x25, 0x51, 0xeb, 0xd3, 0x4b, }, -}, -{ - "sha2_128f_robust", - { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - 0xbc, 0x4a, 0x4a, 0x6c, 0xc7, 0xa1, 0x10, 0x64, - 0x9a, 0x95, 0x96, 0xc2, 0x15, 0xc6, 0x69, 0x5c, }, - { 0xe5, 0xa0, 0x41, 0xe5, 0x2b, 0x14, 0x02, 0x35, - 0x14, 0xe2, 0xe8, 0x46, 0xd6, 0x13, 0x70, 0x07, }, - { 0x4d, 0x44, 0x95, 0x80, 0x6f, 0x23, 0x7e, 0xe9, - 0x83, 0x2b, 0x41, 0x95, 0xc7, 0x51, 0xd1, 0xc5, - 0xcf, 0x7b, 0xb1, 0x05, 0x39, 0xcb, 0xf0, 0xab, - 0x2b, 0x6a, 0xaf, 0x9d, 0x8d, 0x50, 0xa6, 0xaf, }, -}, -{ - "sha2_128f_simple", - { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - 0x3b, 0x56, 0xe8, 0x16, 0x84, 0x7f, 0x00, 0x03, - 0x86, 0xae, 0xec, 0x2e, 0x2b, 0xb9, 0xe1, 0xb5, }, - { 0x8a, 0xfe, 0x14, 0x2a, 0x4d, 0x6e, 0x61, 0xb7, - 0x09, 0x8b, 0x97, 0xe0, 0x49, 0xa4, 0x47, 0x02, }, - { 0x3a, 0x8d, 0x69, 0x64, 0x69, 0x52, 0xee, 0xfa, - 0xec, 0x08, 0xcc, 0x86, 0x06, 0x5c, 0xfa, 0xa7, - 0xed, 0x56, 0x58, 0x5d, 0xd1, 0x85, 0xad, 0x41, - 0x7d, 0x1d, 0xed, 0xa5, 0x0f, 0x1b, 0xdc, 0xb4, }, -}, -{ - "sha2_192f_robust", - { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0xd8, 0x15, 0x52, 0x60, 0x46, 0xc4, 0x38, 0xb7, - 0x53, 0x85, 0x86, 0xcb, 0x0d, 0x96, 0x4a, 0xd4, - 0xf3, 0x94, 0xbe, 0x6d, 0x06, 0xfd, 0xb9, 0x23, }, - { 0xaa, 0x96, 0x0b, 0x27, 0xae, 0x51, 0x9c, 0x71, - 0x82, 0xdf, 0x63, 0xe7, 0x38, 0xb6, 0x81, 0xb9, - 0xb6, 0xf7, 0x0a, 0x6b, 0xd8, 0x81, 0x0a, 0xfb, }, - { 0xa0, 0xb4, 0xa0, 0xce, 0x70, 0x0d, 0x8d, 0xe5, - 0x79, 0x8e, 0x2e, 0x2e, 0xe9, 0x3c, 0x2a, 0x25, - 0xd2, 0x23, 0xc6, 0xea, 0x41, 0xa6, 0xc4, 0x7e, - 0x56, 0x8c, 0xb0, 0xb4, 0xb3, 0x50, 0x55, 0x7c, }, -}, -{ - "sha2_192f_simple", - { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x92, 0x36, 0xcc, 0xeb, 0xbb, 0x3a, 0x90, 0xac, - 0x24, 0x52, 0xdd, 0x89, 0xde, 0x49, 0xda, 0xb1, - 0x34, 0x0e, 0xc0, 0x24, 0x19, 0xa2, 0x87, 0x0e, }, - { 0x7b, 0x28, 0x3f, 0xd1, 0x69, 0x03, 0xd6, 0xdf, - 0x1e, 0xd4, 0x38, 0x89, 0x1a, 0x29, 0x0f, 0x78, - 0xe9, 0xf1, 0xf3, 0x52, 0xd2, 0x9b, 0xdd, 0xdf, }, - { 0x64, 0x50, 0x02, 0x3d, 0xfa, 0x11, 0x3b, 0x6c, - 0xc8, 0x0c, 0xa1, 0x34, 0x03, 0x52, 0xaf, 0x5b, - 0xd9, 0x74, 0x9a, 0xe3, 0x56, 0x68, 0x5b, 0x25, - 0x03, 0x61, 0x50, 0xc0, 0x09, 0xb5, 0x1a, 0x0d, }, -}, -{ - "sha2_256f_robust", - { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, - 0x2b, 0x8d, 0x1b, 0x46, 0xce, 0x35, 0x1a, 0x6f, - 0x1b, 0x68, 0x4b, 0x1d, 0x61, 0xfe, 0xf9, 0xea, - 0x2b, 0x6c, 0xe4, 0x01, 0x8d, 0x26, 0x51, 0xd2, - 0x2f, 0x5f, 0x28, 0x06, 0x15, 0xc5, 0xa3, 0x5d, }, - { 0x05, 0xe3, 0xa8, 0x6b, 0xaf, 0xce, 0xd7, 0xc5, - 0xe7, 0xdf, 0x5a, 0x94, 0xbf, 0xc1, 0x1f, 0x3d, - 0x19, 0xb6, 0x4e, 0x27, 0x5f, 0x4e, 0x4f, 0xb3, - 0x57, 0x5c, 0xb6, 0x31, 0xa4, 0xa1, 0x0f, 0x81, }, - { 0xee, 0x43, 0x54, 0xdf, 0x91, 0x36, 0x32, 0x2a, - 0x80, 0xf2, 0xd1, 0xa5, 0x88, 0x35, 0x93, 0xb6, - 0x9e, 0x23, 0x99, 0x85, 0x67, 0x63, 0xf0, 0x12, - 0x1b, 0x48, 0xde, 0xf4, 0xaa, 0x9f, 0x1a, 0xfb, }, -}, -{ - "sha2_256f_simple", - { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, - 0x42, 0xcf, 0xfe, 0x64, 0xdd, 0xbd, 0x67, 0x31, - 0x06, 0x37, 0x52, 0x68, 0x4d, 0xf7, 0x7c, 0x8b, - 0x58, 0xc2, 0x25, 0xdc, 0x6b, 0x49, 0x12, 0x08, - 0x91, 0x6b, 0x65, 0x4e, 0xa1, 0x39, 0x31, 0x76, }, - { 0x58, 0xd8, 0x06, 0x84, 0xe2, 0xf9, 0x9c, 0x28, - 0x3e, 0xc4, 0x96, 0x32, 0x90, 0x99, 0x98, 0x31, - 0x15, 0x5c, 0x77, 0xa6, 0x0b, 0x43, 0x86, 0x21, - 0x3e, 0xff, 0x35, 0x27, 0xf2, 0x19, 0x8d, 0xaf, }, - { 0xab, 0xd0, 0xe7, 0x42, 0xb2, 0xbc, 0x4e, 0xe0, - 0xb9, 0x41, 0xca, 0x81, 0x28, 0x4b, 0x7e, 0x05, - 0xc3, 0xd4, 0x7c, 0xff, 0x60, 0x0e, 0x2c, 0x10, - 0x66, 0x3f, 0x05, 0x4d, 0xe7, 0x92, 0xee, 0x0f, }, -}, -{ - "sha2_128s_robust", - { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - 0x7f, 0xd2, 0xf7, 0x44, 0x05, 0x88, 0x29, 0x15, - 0x06, 0x81, 0xfc, 0xa2, 0xce, 0xba, 0x6c, 0x92, }, - { 0xa5, 0xcc, 0x0d, 0xf9, 0xf0, 0xc9, 0x53, 0xf7, - 0xf1, 0x7e, 0x8d, 0x3e, 0xcb, 0xeb, 0x24, 0xf1, }, - { 0x60, 0xaa, 0x12, 0xcb, 0x0b, 0x88, 0x36, 0x45, - 0xf4, 0x48, 0x82, 0x12, 0x2d, 0x13, 0x79, 0x20, - 0x88, 0x9f, 0xa8, 0x00, 0x66, 0x50, 0x71, 0x77, - 0x51, 0xef, 0xf5, 0x20, 0x26, 0x39, 0x3c, 0x62, }, -}, -{ - "sha2_128s_simple", - { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - 0x99, 0x0c, 0xe6, 0x29, 0x87, 0x92, 0xb1, 0x28, - 0x84, 0x6a, 0x8e, 0x4a, 0x3a, 0x68, 0x95, 0x4c, }, - { 0x4d, 0xed, 0x53, 0x6f, 0x9d, 0x58, 0x50, 0x49, - 0x6b, 0x59, 0xb0, 0xef, 0x59, 0x5f, 0x79, 0xe0, }, - { 0x4b, 0xd4, 0x81, 0xee, 0xc0, 0x14, 0x83, 0x46, - 0x7c, 0x00, 0xcc, 0xf6, 0x38, 0xe3, 0x2e, 0xd5, - 0xe6, 0x7c, 0x5b, 0xdb, 0x0e, 0x02, 0xed, 0x02, - 0x92, 0xe4, 0xbc, 0xa5, 0xc1, 0xf8, 0x4a, 0x04, }, -}, -{ - "sha2_192s_robust", - { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x39, 0xa1, 0x80, 0x22, 0x23, 0x17, 0xdc, 0x21, - 0xec, 0x82, 0x27, 0xb3, 0xe4, 0xbf, 0x9a, 0x7b, - 0xf2, 0xe5, 0x36, 0x15, 0xae, 0xf1, 0x90, 0x6d, }, - { 0xa1, 0x01, 0x46, 0xcd, 0x28, 0x4d, 0x4a, 0x2a, - 0xa0, 0x92, 0x89, 0x57, 0xa3, 0x33, 0x8a, 0xe5, - 0x1e, 0x95, 0x1c, 0xbd, 0x66, 0x97, 0x7e, 0xe4, }, - { 0x8b, 0xf3, 0x56, 0xca, 0x6e, 0xc5, 0x86, 0xb9, - 0xd2, 0x4d, 0x37, 0x04, 0x09, 0x43, 0x8c, 0xf3, - 0x71, 0x3e, 0xd6, 0x57, 0x5d, 0xd0, 0x9a, 0xe7, - 0x99, 0x79, 0x95, 0x2d, 0xfd, 0x60, 0x1b, 0xdf, }, -}, -{ - "sha2_192s_simple", - { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0xb6, 0xf2, 0x82, 0xce, 0x11, 0x6f, 0xf5, 0x9b, - 0xce, 0x2d, 0x9f, 0xc4, 0xa6, 0x7c, 0x60, 0x31, - 0xda, 0xbd, 0xce, 0x32, 0x6c, 0x34, 0xf5, 0x41, }, - { 0x4d, 0xa1, 0x9f, 0x37, 0xe4, 0x93, 0x65, 0xf3, - 0x70, 0x99, 0xa5, 0x0f, 0x8e, 0x6f, 0xdd, 0xa6, - 0xde, 0xc1, 0x2d, 0xff, 0x2b, 0x48, 0x10, 0x04, }, - { 0xa7, 0xc2, 0x09, 0x8d, 0x69, 0xcb, 0x02, 0x79, - 0x63, 0xa4, 0xcc, 0x0a, 0xe4, 0x54, 0x07, 0x80, - 0x0d, 0xb8, 0xff, 0x83, 0xd1, 0x2d, 0x7e, 0x86, - 0x3d, 0xa6, 0x3e, 0x00, 0x54, 0x2c, 0xbf, 0x92, }, -}, -{ - "sha2_256s_robust", - { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, - 0x42, 0x3d, 0x30, 0x5f, 0xb7, 0xe0, 0x98, 0x8f, - 0xfa, 0x4a, 0x75, 0x60, 0x00, 0x30, 0x16, 0xb8, - 0xef, 0x84, 0x2d, 0x1c, 0xae, 0xf5, 0x91, 0x52, - 0x1e, 0xdc, 0x19, 0xd3, 0xf6, 0x97, 0xae, 0x72, }, - { 0xa9, 0xae, 0xe0, 0x23, 0xfa, 0x2a, 0xa8, 0x31, - 0xad, 0xc0, 0x61, 0x7a, 0xb5, 0x02, 0xe8, 0x0b, - 0x04, 0x35, 0x34, 0x81, 0x4b, 0x95, 0xe1, 0xb0, - 0x89, 0xbf, 0xc2, 0xd8, 0xa1, 0x1c, 0x17, 0xe8, }, - { 0x93, 0x9f, 0xa1, 0x60, 0x6e, 0x1f, 0xff, 0xcd, - 0x98, 0x0b, 0x7b, 0x2f, 0x66, 0xce, 0x42, 0xe5, - 0xff, 0xb2, 0xc7, 0xc7, 0x83, 0x42, 0x9d, 0x11, - 0x32, 0x0f, 0x7a, 0x59, 0xf5, 0xa6, 0x67, 0xa4, }, -}, -{ - "sha2_256s_simple", - { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, - 0xda, 0x71, 0x63, 0xe6, 0x01, 0x35, 0x25, 0x15, - 0xbc, 0x0f, 0x06, 0xf9, 0xf4, 0xf4, 0x4b, 0xe7, - 0x1a, 0x5a, 0x65, 0xee, 0x9d, 0xca, 0x55, 0x75, - 0xcf, 0x4a, 0x7b, 0x6d, 0x4a, 0x87, 0xd6, 0xe2, }, - { 0x4a, 0xde, 0x74, 0x26, 0x86, 0x04, 0xec, 0xc1, - 0x12, 0xea, 0xab, 0xe4, 0x0e, 0x40, 0x87, 0x93, - 0x08, 0xfa, 0x0b, 0xa2, 0x76, 0xe5, 0x27, 0xcb, - 0x46, 0x8e, 0xcb, 0x15, 0x8f, 0x34, 0x71, 0x29, }, - { 0xe3, 0xf1, 0xc0, 0xe7, 0xea, 0x8e, 0xdf, 0xf7, - 0x8b, 0xce, 0xc7, 0xfb, 0x63, 0x3f, 0xa3, 0xf0, - 0x40, 0x01, 0xa3, 0x35, 0xae, 0x79, 0xe5, 0xc9, - 0x01, 0xb3, 0x66, 0x34, 0x59, 0xaf, 0xfe, 0x5f, }, -}, -{ - "haraka_128f_robust", - { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - 0xb7, 0x93, 0x99, 0x51, 0xe8, 0xbd, 0xfe, 0xaf, - 0xd0, 0x5c, 0xc2, 0x40, 0x15, 0x30, 0x44, 0x39, }, - { 0xda, 0x9a, 0xbd, 0x22, 0x52, 0x25, 0x82, 0xc7, - 0x85, 0x9a, 0x56, 0xf0, 0x84, 0x02, 0x75, 0xa1, }, - { 0x63, 0x14, 0x0c, 0x22, 0x13, 0xc9, 0xda, 0x27, - 0x9c, 0xdd, 0xf4, 0xb0, 0x6e, 0x33, 0x93, 0xc8, - 0x62, 0x5e, 0x38, 0x1f, 0xd8, 0x38, 0xbe, 0xde, - 0x1d, 0xa2, 0xca, 0x21, 0x65, 0x7e, 0x94, 0x94, }, -}, -{ - "haraka_128f_simple", - { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - 0xee, 0x37, 0x8d, 0xa1, 0xb1, 0x9d, 0x40, 0x17, - 0x3e, 0x79, 0x84, 0x09, 0xff, 0x31, 0x38, 0x48, }, - { 0xae, 0x93, 0x33, 0x22, 0x85, 0x14, 0x6a, 0x83, - 0x13, 0x8f, 0x15, 0x48, 0xa3, 0x16, 0x3f, 0x99, }, - { 0x9a, 0xc0, 0xbe, 0xe8, 0x88, 0xee, 0xd0, 0x54, - 0xc1, 0x15, 0x5b, 0x15, 0xdd, 0xea, 0x52, 0xa4, - 0xd8, 0x57, 0xd8, 0x5f, 0xd9, 0x65, 0x85, 0x30, - 0x8b, 0xe2, 0xad, 0x7a, 0xfb, 0xed, 0x97, 0xe4, }, -}, -{ - "haraka_192f_robust", - { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x79, 0xed, 0x28, 0x2f, 0x02, 0xaa, 0xed, 0x09, - 0xdc, 0x47, 0xe4, 0xb4, 0xf3, 0xe6, 0x7f, 0x19, - 0xfc, 0xe8, 0xa4, 0x3a, 0x52, 0x35, 0x9d, 0x5a, }, - { 0xf6, 0x49, 0xad, 0x50, 0xed, 0xfc, 0xe2, 0xec, - 0x63, 0xc0, 0xb4, 0x4a, 0xde, 0xd6, 0x6e, 0x33, - 0xff, 0x07, 0x68, 0xab, 0x6a, 0x75, 0x74, 0x0c, }, - { 0xd5, 0x22, 0x97, 0x17, 0x3c, 0x7d, 0xcf, 0x11, - 0x15, 0x35, 0xe6, 0xa0, 0x15, 0xe5, 0x8b, 0x8b, - 0x3e, 0x6d, 0x35, 0x1a, 0xd0, 0xd4, 0xf7, 0x2f, - 0x98, 0x70, 0x17, 0xd0, 0xbb, 0xe9, 0x59, 0x72, }, -}, -{ - "haraka_192f_simple", - { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x0c, 0x30, 0x92, 0xaa, 0xaa, 0x3a, 0x3f, 0x22, - 0x63, 0x75, 0x7d, 0x0c, 0x82, 0xe3, 0x12, 0x9d, - 0x1a, 0xe7, 0xa0, 0x23, 0xea, 0xd5, 0x15, 0x5f, }, - { 0x8a, 0xb0, 0x27, 0x8c, 0x8b, 0xdd, 0x73, 0x0f, - 0x8f, 0xda, 0x1f, 0x12, 0x96, 0xba, 0x57, 0x22, - 0xa2, 0xd0, 0xa8, 0xf7, 0x1e, 0xf5, 0x1f, 0xfd, }, - { 0xa7, 0x47, 0x13, 0x66, 0xe3, 0x28, 0x9a, 0x36, - 0x18, 0x8c, 0x03, 0xca, 0x18, 0xa7, 0x80, 0x5e, - 0xd3, 0x22, 0xc7, 0x79, 0x7a, 0x2c, 0x69, 0x1e, - 0x9c, 0x8e, 0x49, 0xdc, 0x54, 0x5f, 0xf4, 0x3e, }, -}, -{ - "haraka_256f_robust", - { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, - 0xb9, 0x93, 0xc1, 0x93, 0x47, 0xa3, 0xf6, 0x0e, - 0xc5, 0x1a, 0x06, 0xb7, 0x36, 0x27, 0x96, 0x11, - 0x9a, 0x1e, 0x3d, 0xb7, 0xd6, 0x7f, 0x6e, 0x23, - 0x65, 0x46, 0x64, 0xf9, 0x09, 0x2a, 0xfd, 0xbb, }, - { 0xfb, 0x75, 0xde, 0xb7, 0x55, 0xb7, 0x30, 0xd7, - 0x41, 0x19, 0xd8, 0x8e, 0x81, 0x0b, 0xe0, 0x24, - 0x61, 0xaa, 0xb3, 0x94, 0x66, 0x34, 0x83, 0xbd, - 0x01, 0x37, 0xad, 0x7f, 0x26, 0x29, 0x74, 0x46, }, - { 0x17, 0x9d, 0x07, 0xd8, 0xde, 0xcd, 0x47, 0x11, - 0x47, 0x27, 0xa7, 0x2b, 0xf6, 0x2d, 0xb6, 0x50, - 0xf4, 0x99, 0xb1, 0x82, 0x52, 0x23, 0x1d, 0x06, - 0xe4, 0x39, 0xa7, 0xdf, 0x49, 0x93, 0x68, 0xbc, }, -}, -{ - "haraka_256f_simple", - { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, - 0x6e, 0x4f, 0xd7, 0x05, 0x05, 0x00, 0x7f, 0x1a, - 0xd6, 0x9f, 0xce, 0x26, 0x25, 0x91, 0xf0, 0x4e, - 0xc0, 0xc7, 0xda, 0x44, 0x35, 0x38, 0xcc, 0x2a, - 0x09, 0xa0, 0x71, 0x00, 0xa9, 0x1b, 0x7a, 0x31, }, - { 0x8d, 0x9f, 0xea, 0x45, 0x03, 0x58, 0x31, 0x36, - 0x1d, 0x7d, 0x30, 0x2c, 0x73, 0xd9, 0x50, 0x6a, - 0xdf, 0xe1, 0x06, 0x4c, 0xe3, 0xe8, 0xc2, 0x2b, - 0x49, 0x86, 0x2a, 0x32, 0x7c, 0xc4, 0xe3, 0x2a, }, - { 0xc8, 0x8a, 0x85, 0x51, 0x7c, 0xff, 0x58, 0xb8, - 0xe3, 0xe8, 0xe6, 0x2d, 0x0e, 0x16, 0x48, 0xe3, - 0x53, 0xdf, 0x90, 0x3c, 0x9d, 0xc9, 0xde, 0xfb, - 0x96, 0xde, 0xf4, 0xea, 0x8d, 0x31, 0xb6, 0xcd, }, -}, -{ - "haraka_128s_robust", - { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - 0xfc, 0xbe, 0x48, 0x31, 0xdb, 0xb0, 0x4e, 0x35, - 0x3f, 0xbf, 0xa8, 0x38, 0xc3, 0x0e, 0xb7, 0x0e, }, - { 0x63, 0x9b, 0xb5, 0xee, 0x93, 0x29, 0x41, 0x1c, - 0x89, 0x41, 0x72, 0x76, 0xf9, 0xc5, 0x32, 0x68, }, - { 0x59, 0x8b, 0xb3, 0xd3, 0x77, 0xaa, 0xff, 0xe0, - 0x78, 0x07, 0xef, 0x01, 0x22, 0x38, 0x1d, 0x23, - 0x06, 0xa5, 0x9f, 0x88, 0x5f, 0x41, 0x35, 0x2f, - 0x5f, 0xc0, 0x25, 0x40, 0x3f, 0x29, 0x04, 0x70, }, -}, -{ - "haraka_128s_simple", - { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - 0x93, 0x6b, 0xa0, 0x49, 0xc7, 0x5c, 0x04, 0x02, - 0x14, 0x0d, 0x33, 0x92, 0x22, 0x46, 0x33, 0x5e, }, - { 0x77, 0x19, 0xf8, 0x02, 0xd3, 0xfc, 0xdd, 0xdc, - 0xe4, 0x99, 0x4a, 0x10, 0x86, 0x2f, 0x06, 0x69, }, - { 0x27, 0x1c, 0x76, 0xbd, 0x7c, 0xf0, 0xbc, 0xd5, - 0xe6, 0xdc, 0xa5, 0x3b, 0xfc, 0xdc, 0x08, 0xa1, - 0x9f, 0xf6, 0x11, 0x6a, 0xed, 0x56, 0x30, 0xf0, - 0xdb, 0xd9, 0x5e, 0x31, 0xbc, 0x85, 0x5e, 0x50, }, -}, -{ - "haraka_192s_robust", - { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0xb5, 0x31, 0x4a, 0x4f, 0xd5, 0x1f, 0x0d, 0x21, - 0xb2, 0x50, 0xf5, 0x1d, 0xf8, 0x73, 0xe9, 0x24, - 0x9a, 0x2e, 0xcc, 0x13, 0x78, 0xca, 0xa6, 0xda, }, - { 0x3d, 0xf2, 0xa5, 0x02, 0x88, 0x71, 0x4e, 0xaf, - 0x45, 0x3f, 0xe0, 0xec, 0xd6, 0x8c, 0x8b, 0xfe, - 0x74, 0xb3, 0x61, 0x9a, 0xbb, 0x0d, 0x8d, 0xa5, }, - { 0x7f, 0xf9, 0xe4, 0x90, 0xd8, 0x99, 0x7a, 0x83, - 0xaf, 0xa4, 0xcb, 0x83, 0x02, 0xfb, 0x18, 0x74, - 0xe9, 0xdb, 0x62, 0x61, 0x1f, 0xa4, 0x56, 0xc9, - 0xf6, 0xaa, 0x90, 0x4a, 0x00, 0x72, 0xd8, 0x08, }, -}, -{ - "haraka_192s_simple", - { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x66, 0xfe, 0x20, 0xe8, 0xf6, 0xaf, 0x30, 0x71, - 0xaa, 0x75, 0x3e, 0x48, 0xd6, 0xa2, 0x88, 0x68, - 0xb1, 0xb4, 0x6d, 0x2d, 0xe2, 0xa5, 0xfa, 0x52, }, - { 0x5f, 0xb1, 0x71, 0xa6, 0x8a, 0x07, 0xb3, 0xa9, - 0x12, 0x5b, 0x7f, 0x82, 0x8b, 0x82, 0x8f, 0x3f, - 0x34, 0x9e, 0x13, 0xf9, 0xfe, 0xe8, 0x75, 0x91, }, - { 0x44, 0xae, 0x7c, 0x4a, 0xd8, 0x5c, 0xe4, 0x19, - 0xd6, 0x15, 0xd8, 0x3c, 0xe0, 0x07, 0xb0, 0xad, - 0x07, 0x12, 0x4b, 0xbf, 0xc2, 0x08, 0x06, 0x5d, - 0x08, 0x0b, 0x1d, 0x47, 0xca, 0x4e, 0x31, 0xcb, }, -}, -{ - "haraka_256s_robust", - { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, - 0xa3, 0x3e, 0xaa, 0xad, 0x00, 0x59, 0xbd, 0x80, - 0x3c, 0x31, 0x1e, 0x3a, 0x6b, 0xf2, 0x90, 0x16, - 0x94, 0x31, 0xcb, 0xf7, 0xc6, 0x0b, 0xec, 0x14, - 0xe9, 0x19, 0x97, 0x0a, 0xcd, 0xc9, 0x93, 0x02, }, - { 0xbb, 0x30, 0xa6, 0xbf, 0x0e, 0xb3, 0x63, 0xe6, - 0x1f, 0xb3, 0xf2, 0x65, 0x45, 0x42, 0x7c, 0x3b, - 0x84, 0x5c, 0xce, 0xb2, 0xcc, 0x72, 0xd3, 0xda, - 0xb0, 0xe7, 0x2a, 0x44, 0x74, 0xb4, 0xe9, 0x8d, }, - { 0xbf, 0x85, 0x29, 0x49, 0x1f, 0x07, 0x68, 0xbd, - 0x6d, 0xc7, 0xa4, 0xb9, 0x58, 0x2d, 0xf8, 0x01, - 0x88, 0xd5, 0xae, 0x39, 0xb0, 0x23, 0xe8, 0x31, - 0xa0, 0xb5, 0x1f, 0x79, 0x74, 0x1b, 0x11, 0x75, }, -}, -{ - "haraka_256s_simple", - { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, - 0x90, 0x4d, 0x54, 0x4b, 0x06, 0xeb, 0x11, 0xfa, - 0x9b, 0xc7, 0xba, 0x40, 0x20, 0x79, 0x00, 0x27, - 0x37, 0x53, 0xca, 0x02, 0x53, 0x95, 0xa5, 0x29, - 0x46, 0x45, 0x0c, 0x57, 0x0e, 0xc4, 0x37, 0xd6, }, - { 0x55, 0x90, 0x4c, 0xb5, 0x94, 0x8e, 0x13, 0x86, - 0x59, 0xdc, 0x75, 0x53, 0x2e, 0xb2, 0xdb, 0xbd, - 0x33, 0x82, 0xd1, 0x74, 0x1b, 0x2d, 0x5c, 0x61, - 0x3f, 0x74, 0x46, 0x1b, 0x1c, 0x3f, 0x3e, 0x45, }, - { 0xaf, 0xc4, 0x6d, 0x50, 0xf2, 0x5b, 0x89, 0x10, - 0x43, 0x78, 0x0a, 0xf2, 0x31, 0x8b, 0xbf, 0xe0, - 0x94, 0xd9, 0xd6, 0x9b, 0x00, 0xec, 0x1a, 0x8d, - 0x92, 0xa7, 0x37, 0x9f, 0x6d, 0xd9, 0x30, 0x50, }, -}, diff --git a/testvector/Makefile b/testvector/Makefile new file mode 100644 index 0000000..e4bdc1d --- /dev/null +++ b/testvector/Makefile @@ -0,0 +1,75 @@ +PARAMS = sphincs-haraka-128f +THASH = robust + +CC=/usr/bin/gcc +CFLAGS=-Wall -Wextra -Wpedantic -O3 -std=c99 -DPARAMS=$(PARAMS) $(EXTRA_CFLAGS) + +SOURCES = address.c randombytes.c merkle.c wots.c wotsx1.c utils.c utilsx1.c fors.c sign.c +HEADERS = params.h address.h randombytes.h merkle.h wots.h wotsx1.h utils.h utilsx1.h fors.h api.h hash.h thash.h + +ifneq (,$(findstring shake,$(PARAMS))) + SOURCES += fips202.c hash_shake.c thash_shake_$(THASH).c + HEADERS += fips202.h +endif +ifneq (,$(findstring haraka,$(PARAMS))) + SOURCES += haraka.c hash_haraka.c thash_haraka_$(THASH).c + HEADERS += haraka.h +endif +ifneq (,$(findstring sha2,$(PARAMS))) + SOURCES += sha2.c hash_sha2.c thash_sha2_$(THASH).c + HEADERS += sha2.h +endif + +DET_SOURCES = $(SOURCES:randombytes.%=rng.%) +DET_HEADERS = $(HEADERS:randombytes.%=rng.%) + +TESTS = test/fors \ + test/spx \ + test/testvector + +BENCHMARK = test/benchmark + +TESTVECTOR = test/testvector + +.PHONY: clean test benchmark testvector + +default: PQCgenKAT_sign + +all: PQCgenKAT_sign tests benchmarks + +tests: $(TESTS) + +test: $(TESTS:=.exec) + +benchmarks: $(BENCHMARK) + +benchmark: $(BENCHMARK:=.exec) + +testvectors: $(TESTVECTOR) + +testvector: $(TESTVECTOR:=.exec) + +PQCgenKAT_sign: PQCgenKAT_sign.c $(DET_SOURCES) $(DET_HEADERS) + $(CC) $(CFLAGS) -o $@ $(DET_SOURCES) $< -lcrypto + +test/benchmark: test/benchmark.c test/cycles.c $(SOURCES) $(HEADERS) + $(CC) $(CFLAGS) -o $@ test/cycles.c $(SOURCES) $< $(LDLIBS) + +test/%: test/%.c $(SOURCES) $(HEADERS) + $(CC) $(CFLAGS) -o $@ $(SOURCES) $< $(LDLIBS) + +test/testvector: test/testvector.c $(DET_SOURCES) $(DET_HEADERS) + $(CC) $(CFLAGS) -o $@ $(DET_SOURCES) $< $(LDLIBS) -lcrypto + +test/haraka: test/haraka.c $(filter-out haraka.c,$(SOURCES)) $(HEADERS) + $(CC) $(CFLAGS) -o $@ $(filter-out haraka.c,$(SOURCES)) $< $(LDLIBS) + +test/%.exec: test/% + @$< + +clean: + -$(RM) $(TESTS) + -$(RM) $(BENCHMARK) + -$(RM) PQCgenKAT_sign + -$(RM) PQCsignKAT_*.rsp + -$(RM) PQCsignKAT_*.req diff --git a/testvector/ReadMe b/testvector/ReadMe new file mode 100644 index 0000000..8b593d9 --- /dev/null +++ b/testvector/ReadMe @@ -0,0 +1,22 @@ +This directory doesn't contain any sources for the parallel Sphincs +implementation. Instead, contains the logic we add to the Sphincs+ reference +code to generate the test vectors (testvector.h); these test vectors are +meant to verify that the parallel Sphincs code does the exact same operations +as the reference code. + +These files are: +- testvector.py This is the python script that actually generates the + testvector.h. It lives in the top level directory of + the reference code +- Makefile This includes the changes needed to generate the + executable the python script needs. It lives in the + ref directory +- testvector.c This is the source of the executable that actually + generates the code. It lives in the ref/test directory + +To generate the test vectors, copy testvector.py and testvector.c to the +indicated directory; also modify the existing ref/Makefile to include the +changes in the above Makefile. + +Then, running "./testvector.py" should generate the testvector.h file (in the +top level directory). diff --git a/testvector/testvector.c b/testvector/testvector.c new file mode 100644 index 0000000..ff6b30b --- /dev/null +++ b/testvector/testvector.c @@ -0,0 +1,251 @@ +#define _POSIX_C_SOURCE 199309L + +#include +#include +#include + +#include "../api.h" +#include "../rng.h" + +#if 0 +#include + +#include "../fors.h" +#include "../wotsx1.h" +#include "../params.h" +#include "../randombytes.h" + +#define SPX_MLEN 32 +#define NTESTS 10 + +static void wots_gen_pkx1(unsigned char *pk, const unsigned char *seed, + const unsigned char *pub_seed, uint32_t addr[8]); + +static int cmp_llu(const void *a, const void*b) +{ + if(*(unsigned long long *)a < *(unsigned long long *)b) return -1; + if(*(unsigned long long *)a > *(unsigned long long *)b) return 1; + return 0; +} + +static unsigned long long median(unsigned long long *l, size_t llen) +{ + qsort(l,llen,sizeof(unsigned long long),cmp_llu); + + if(llen%2) return l[llen/2]; + else return (l[llen/2-1]+l[llen/2])/2; +} + +static void delta(unsigned long long *l, size_t llen) +{ + unsigned int i; + for(i = 0; i < llen - 1; i++) { + l[i] = l[i+1] - l[i]; + } +} + +static unsigned long long cpucycles(void) +{ + unsigned long long result; + __asm volatile(".byte 15;.byte 49;shlq $32,%%rdx;orq %%rdx,%%rax" + : "=a" (result) :: "%rdx"); + return result; +} + +static void printfcomma (unsigned long long n) +{ + if (n < 1000) { + printf("%llu", n); + return; + } + printfcomma(n / 1000); + printf (",%03llu", n % 1000); +} + +static void printfalignedcomma (unsigned long long n, int len) +{ + unsigned long long ncopy = n; + int i = 0; + + while (ncopy > 9) { + len -= 1; + ncopy /= 10; + i += 1; // to account for commas + } + i = i/3 - 1; // to account for commas + for (; i < len; i++) { + printf(" "); + } + printfcomma(n); +} + +static void display_result(double result, unsigned long long *l, size_t llen, unsigned long long mul) +{ + unsigned long long med; + + result /= NTESTS; + delta(l, NTESTS + 1); + med = median(l, llen); + printf("avg. %11.2lf us (%2.2lf sec); median ", result, result / 1e6); + printfalignedcomma(med, 12); + printf(" cycles, %5llux: ", mul); + printfalignedcomma(mul*med, 12); + printf(" cycles\n"); +} + +#define MEASURE(TEXT, MUL, FNCALL)\ + printf(TEXT);\ + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);\ + for(i = 0; i < NTESTS; i++) {\ + t[i] = cpucycles();\ + FNCALL;\ + }\ + t[NTESTS] = cpucycles();\ + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &stop);\ + result = (stop.tv_sec - start.tv_sec) * 1e6 + (stop.tv_nsec - start.tv_nsec) / 1e3;\ + display_result(result, t, NTESTS, MUL); + +static void dump_vector( unsigned char *p, unsigned len ) { + printf( "{\n" ); + for (int i = 0; i < len; i++) { + printf( "%s%02x,%s", p[i], (i%8)==0 ? " " : "", (i%8)==7 ? "\n" : "" ); + } + printf( "},\n" ); +} +#endif + +int main(void) +{ + unsigned char pk[SPX_PK_BYTES]; + unsigned char sk[SPX_SK_BYTES]; + unsigned char seed[CRYPTO_SEEDBYTES]; + int i; + for (i=0; i #include "internal.h" -namespace sphincs_plus { +namespace slh_dsa { /** * Converts the value of 'in' to 'outlen' bytes in big-endian byte order. @@ -78,4 +78,4 @@ void zeroize( void *area, size_t len ) { #endif } -} /* namespace sphincs_plus */ +} /* namespace slh_dsa */ diff --git a/verify.cpp b/verify.cpp index 5f13df1..bcc824c 100644 --- a/verify.cpp +++ b/verify.cpp @@ -1,6 +1,6 @@ /// /// \file verify.cpp -/// \brief This is the module that verifies a Sphincs+ signature +/// \brief This is the module that verifies an SLH-DSA signature /// /// There's not a great deal of advantage of this over the reference code /// (except for our support for multiple parameter sets simultaneously), @@ -11,20 +11,36 @@ #include "api.h" #include "internal.h" -namespace sphincs_plus { +namespace slh_dsa { // // This verifies a signature +success_flag key::verify( + const unsigned char *signature, size_t len_signature, + const void *message, size_t len_message, + const void *context, size_t len_context) { + return verify_internal(signature, len_signature, + 0x00, // We're not prehashing + context, len_context, + 0, 0, // No hash OID + message, len_message); +} + // // One note about this logic: this really does process a signature in // order (mostly); however our geo logic has the signature components all // parsed out, so we use that, rather than stepping through the signature -success_flag key::verify( +success_flag key::verify_internal( const unsigned char *signature, size_t len_signature, + unsigned char domain_separator_byte, + const void *context, size_t len_context, + const void *oid, size_t len_oid, const void *message, size_t len_message) { // Make sure this key has the public key loaded if (!have_public_key) return false; + if (len_context > 255) return false; + size_t n = len_hash(); // Step 1: lay out where the various components of the signature are @@ -39,7 +55,8 @@ success_flag key::verify( // Step 2 - hash the message hash_message( geo, &signature[ geo.randomness_offset ], - (const unsigned char*)message, len_message ); + domain_separator_byte, context, len_context, oid, len_oid, + message, len_message ); // Step 3 - walk up the FORS trees to generate the FORS root // This logic would fit nicely in xn_hash, except that something @@ -48,7 +65,7 @@ success_flag key::verify( for (unsigned i=0; i0; i--) { if (c + count[i] >= num_track) { @@ -92,6 +95,14 @@ void key::compute_chains(unsigned char *array, // the elements not already on the // bottom + // Ok, we've identified the lists. Now, starting at the bottom list + // we identitied, move those lists down one (with the note that for + // the first list we're moving, which is the bottom most list of the + // scan, may be a partial move, as there might be more on that list + // than what we can move + // We do this in bottom-up order so that we don't accidentally re-move + // a list -- thash can advance a list element only by one, so we can + // move an element only by one per iteration) // Load things up, starting with the first num_track-c elements // from row i int d = 0; @@ -148,4 +159,4 @@ void key::compute_chains(unsigned char *array, } } -} /* namespace sphincs_plus */ +} /* namespace slh_dsa */ diff --git a/xn_hash.cpp b/xn_hash.cpp index 8734673..bf55dac 100644 --- a/xn_hash.cpp +++ b/xn_hash.cpp @@ -6,7 +6,7 @@ #include "api.h" #include "internal.h" -namespace sphincs_plus { +namespace slh_dsa { /// /// The object that will generate num_track different WOTS public keys @@ -454,4 +454,4 @@ void gen_fors_leaves::operator()(unsigned char* dest, uint32_t leaf_idx) { k.f_xn(leaves, leaves, leaf_addrx); } -} /* namespace sphincs_plus */ +} /* namespace slh_dsa */