diff --git a/include/decaf.h b/include/decaf.h index f82f2d1..7465832 100644 --- a/include/decaf.h +++ b/include/decaf.h @@ -47,9 +47,11 @@ && !defined(DECAF_FORCE_32_BIT) #define DECAF_WORD_BITS 64 typedef uint64_t decaf_word_t, decaf_bool_t; +typedef __uint128_t decaf_dword_t; #else #define DECAF_WORD_BITS 32 typedef uint32_t decaf_word_t, decaf_bool_t; +typedef uint64_t decaf_dword_t; #endif #define DECAF_448_LIMBS (512/DECAF_WORD_BITS) diff --git a/include/decaf.hxx b/include/decaf.hxx index 126fe05..0eaf3d6 100644 --- a/include/decaf.hxx +++ b/include/decaf.hxx @@ -281,13 +281,7 @@ public: inline Scalar(const Scalar &x) NOEXCEPT { *this = x; } /** @brief Construct from arbitrary-length little-endian byte sequence. */ - inline Scalar(const unsigned char *buffer, size_t n) NOEXCEPT { decode(buffer,n); } - - /** @brief Construct from arbitrary-length little-endian byte sequence. */ - inline Scalar(const Block &buffer) NOEXCEPT { decode(buffer.data(),buffer.size()); } - - /** @brief Decode from long buffer. */ - inline void decode(const unsigned char *buffer, size_t n) NOEXCEPT { decaf_448_scalar_decode_long(s,buffer,n); } + inline Scalar(const Block &buffer) NOEXCEPT { *this = buffer; } /** @brief Assignment. */ inline Scalar& operator=(const Scalar &x) NOEXCEPT { decaf_448_scalar_copy(s,x.s); return *this; } diff --git a/include/shake.h b/include/shake.h index 000f846..c99197c 100644 --- a/include/shake.h +++ b/include/shake.h @@ -15,6 +15,8 @@ #include #include +#include "decaf.h" /* TODO: orly? */ + /* TODO: unify with other headers (maybe all into one??); add nonnull attributes */ /** @cond internal */ #define API_VIS __attribute__((visibility("default"))) @@ -30,8 +32,14 @@ /** @endcond */ } keccak_sponge_t[1]; struct kparams_s; + typedef struct { uint64_t opaque; } strobe_params_t[1]; #endif +typedef struct strobe_s { + keccak_sponge_t sponge; + strobe_params_t params; +} strobe_s, strobe_t[1]; + #ifdef __cplusplus extern "C" { #endif @@ -243,6 +251,84 @@ void spongerng_stir ( size_t len ) API_VIS; +/** + * @brief Initialize Strobe protocol context. + * @param [out] The initialized strobe object. + * @param [in] Strobe parameter descriptor + * @param [in] am_client Nonzero if this party + * is the client. + */ +void strobe_init( + strobe_t strobe, + const struct kparams_s *params, + uint8_t am_client +); + +/** + * @brief Produce an authenticator. + * @param [inout] strobe The Strobe protocol context + * @param [out] out The authenticator + * @param len The length, which must be no more than + * @todo 32? + */ +void strobe_produce_auth ( + strobe_t strobe, + unsigned char *out, + size_t len +); + +/** + * @brief Produce a session-bound pseudorandom value. + * + * @warning This "prng" value is NOT suitable for + * refreshing forward secrecy! It's to replace things + * like TCP session hash. + * + * @todo Figure out how to treat this wrt anti-rollback. + * + * @param [inout] strobe The Strobe protocol context + * @param [out] out The authenticator + * @param len The length. + */ +void strobe_prng ( + strobe_t strobe, + unsigned char *out, + size_t len +); + +/** + * @brief Verify an authenticator. + * @param [inout] strobe The Strobe protocol context + * @param [in] in The authenticator + * @param len The length, which must be no more than + * @todo 32? + */ +decaf_bool_t strobe_verify_auth ( + strobe_t strobe, + const unsigned char *in, + size_t len +); + +/** + * @brief Respecify Strobe protocol object's crypto. + * @param [inout] The initialized strobe context. + * @param [in] Strobe parameter descriptor + * @param [in] am_client Nonzero if this party + * is the client. + */ +void strobe_respec ( + strobe_t strobe, + const struct kparams_s *params +); + +/** + * @brief Destroy a Strobe context. + * @param [out] strobe The object to destroy. + */ +void strobe_destroy ( + strobe_t strobe +); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/include/shake.hxx b/include/shake.hxx index 6593b52..34390c7 100644 --- a/include/shake.hxx +++ b/include/shake.hxx @@ -75,15 +75,19 @@ public: * @brief Output bytes from the sponge. * @todo make this throw exceptions. */ - inline void output(unsigned char *c, size_t len) { - sha3_output(sp,c,len); - } + inline void output(TmpBuffer b) { sha3_output(sp,b.data(),b.size()); } + + /** + * @brief Output bytes from the sponge. + * @todo make this throw exceptions. + */ + inline void output(Buffer &b) { sha3_output(sp,b.data(),b.size()); } /** @brief Output bytes from the sponge. */ inline SecureBuffer output(size_t len) { - SecureBuffer buffer(len); + SecureBuffer buffer(len); sha3_output(sp,buffer,len); - return buffer; + return buffer; } /** @brief Return the sponge's default output size. */ @@ -98,7 +102,7 @@ public: }; /** Fixed-output-length SHA3 */ -template class SHA3 : public KeccakSponge { +template class SHA3 : public KeccakHash { private: /** Get the parameter template block for this hash */ const struct kparams_s *get_params(); @@ -109,7 +113,7 @@ public: /** Variable-output-length SHAKE */ template -class SHAKE : public KeccakSponge { +class SHAKE : public KeccakHash { private: /** Get the parameter template block for this hash */ const struct kparams_s *get_params(); diff --git a/src/decaf.c b/src/decaf.c index c701f1b..a19a2ad 100644 --- a/src/decaf.c +++ b/src/decaf.c @@ -17,12 +17,10 @@ #if WBITS == 64 #define LBITS 56 -typedef __uint128_t decaf_dword_t; typedef __int128_t decaf_sdword_t; #define LIMB(x) (x##ull) #define SC_LIMB(x) (x##ull) #elif WBITS == 32 -typedef uint64_t decaf_dword_t; typedef int64_t decaf_sdword_t; #define LBITS 28 #define LIMB(x) (x##ull)&((1ull<>LBITS diff --git a/src/decaf_fast.c b/src/decaf_fast.c index 6b5ab89..9894b7d 100644 --- a/src/decaf_fast.c +++ b/src/decaf_fast.c @@ -18,12 +18,10 @@ #if WBITS == 64 #define LBITS 56 -typedef __uint128_t decaf_dword_t; typedef __int128_t decaf_sdword_t; #define LIMB(x) (x##ull) #define SC_LIMB(x) (x##ull) #elif WBITS == 32 -typedef uint64_t decaf_dword_t; typedef int64_t decaf_sdword_t; #define LBITS 28 #define LIMB(x) (x##ull)&((1ull<>LBITS diff --git a/src/shake.c b/src/shake.c index c5806b4..14d1660 100644 --- a/src/shake.c +++ b/src/shake.c @@ -61,6 +61,10 @@ typedef struct kparams_s { uint8_t position, flags, rate, startRound, pad, ratePad, maxOut, _; } kparams_t[1]; +typedef struct strobe_params_s { + uint8_t client, _[7]; +} strobe_params_t[1]; + typedef struct keccak_sponge_s { kdomain_t state; kparams_t params; @@ -68,6 +72,7 @@ typedef struct keccak_sponge_s { #define INTERNAL_SPONGE_STRUCT 1 #include "shake.h" +#include "decaf.h" #define FLAG_ABSORBING 'A' #define FLAG_SQUEEZING 'Z' @@ -446,4 +451,212 @@ int spongerng_init_from_dev_urandom ( return spongerng_init_from_file(sponge, "/dev/urandom", 64, 0); } +/* Strobe is different in that its rate is padded by one byte. */ +void strobe_init( + strobe_t strobe, + const struct kparams_s *params, + uint8_t am_client +) { + sponge_init(strobe->sponge,params); + strobe->params->client = !!am_client; +} + +static void strobe_duplex ( + keccak_sponge_t sponge, + unsigned char *out, + const unsigned char *in, + size_t len +) { + unsigned j; + while (len) { + assert(sponge->params->rate >= sponge->params->position); + size_t cando = sponge->params->rate - sponge->params->position; + uint8_t* state = &sponge->state->b[sponge->params->position]; + if (cando >= len) { + for (j=0; in && jparams->position += len; + return; + } else { + if (in) { + for (j=0; jparams->rate >= sponge->params->position); + size_t cando = sponge->params->rate - sponge->params->position; + uint8_t* state = &sponge->state->b[sponge->params->position]; + if (cando >= len) { + for (j=0; in && jparams->position += len; + return; + } else { + for (j=0; in && jsponge->params->rate < sizeof(strobe->sponge->state)); + strobe_duplex(strobe->sponge,NULL,(const unsigned char *)control,sizeof(*control)); + strobe->sponge->state->b[strobe->sponge->params->position] ^= 0x1; + strobe->sponge->state->b[strobe->sponge->params->rate] ^= 0x2; + dokeccak(strobe->sponge); +} + +void strobe_encrypt ( + strobe_t strobe, + unsigned char *out, + const unsigned char *in, + size_t len +) { + struct strobe_control cont = { CIPHERTEXT, 0, + strobe->params->client ? CLIENT_TO_SERVER : SERVER_TO_CLIENT }; + strobe_control_word(strobe, &cont); + strobe_duplex(strobe->sponge, out, in, len); +} + +void strobe_decrypt ( + strobe_t strobe, + unsigned char *out, + const unsigned char *in, + size_t len +) { + struct strobe_control cont = { CIPHERTEXT, 0, + strobe->params->client ? SERVER_TO_CLIENT : CLIENT_TO_SERVER }; + strobe_control_word(strobe, &cont); + strobe_duplex(strobe->sponge, out, in, len); +} + +void strobe_plaintext ( + strobe_t strobe, + const unsigned char *in, + size_t len, + uint8_t iSent +) { + struct strobe_control cont = { CIPHERTEXT, 0, + (strobe->params->client == !!iSent) ? CLIENT_TO_SERVER : SERVER_TO_CLIENT }; + strobe_control_word(strobe, &cont); + strobe_duplex(strobe->sponge, NULL, in, len); +} + +#define STROBE_FORGET_BYTES 32 + +void strobe_produce_auth ( + strobe_t strobe, + unsigned char *out, + size_t len +) { + assert(len < strobe->sponge->params->rate - STROBE_FORGET_BYTES); + struct strobe_control cont = { TAGFORGET, len, + strobe->params->client ? CLIENT_TO_SERVER : SERVER_TO_CLIENT }; + strobe_control_word(strobe, &cont); + strobe_duplex(strobe->sponge, out, NULL, len); + strobe_duplex(strobe->sponge, NULL, + &strobe->sponge->state->b[strobe->sponge->params->position], + STROBE_FORGET_BYTES + ); +} + +void strobe_prng ( + strobe_t strobe, + unsigned char *out, + size_t len +) { + struct strobe_control cont = { PRNG, 0, 0 }; + strobe_control_word(strobe, &cont); + strobe_duplex(strobe->sponge, out, NULL, len); + + /* Forget. TODO: ORLY? */ + cont.next = TAGFORGET; + strobe_control_word(strobe, &cont); + strobe_duplex(strobe->sponge, NULL, + &strobe->sponge->state->b[0], + STROBE_FORGET_BYTES + ); +} + +/* TODO: remove reliance on decaf? */ +decaf_bool_t strobe_verify_auth ( + strobe_t strobe, + const unsigned char *in, + size_t len +) { + unsigned char zero[len]; + decaf_bool_t chain=0; + assert(len < strobe->sponge->params->rate - STROBE_FORGET_BYTES); + struct strobe_control cont = { TAGFORGET, len, + strobe->params->client ? CLIENT_TO_SERVER : SERVER_TO_CLIENT }; + strobe_control_word(strobe, &cont); + strobe_unduplex(strobe->sponge, zero, in, len); + strobe_duplex(strobe->sponge, NULL, + &strobe->sponge->state->b[strobe->sponge->params->position], + STROBE_FORGET_BYTES); + + /* Check for 0 */ + unsigned i; + for (i=0; i>(8*sizeof(decaf_word_t)); +} + +void strobe_destroy ( + strobe_t strobe +) { + decaf_bzero(strobe,sizeof(strobe_t)); +} + +void strobe_respec ( + strobe_t strobe, + const struct kparams_s *params +) { + struct strobe_control cont = { RESPEC, params->rate, params->startRound }; + strobe_control_word(strobe, &cont); + strobe->sponge->params[0] = params[0]; +} + /* TODO: Keyak instances, etc */ diff --git a/test/bench_decaf.cxx b/test/bench_decaf.cxx index e4a88c3..dd66621 100644 --- a/test/bench_decaf.cxx +++ b/test/bench_decaf.cxx @@ -10,6 +10,7 @@ */ #include "decaf.hxx" +#include "shake.hxx" #include "shake.h" #include "decaf_crypto.h" #include @@ -134,9 +135,16 @@ int main(int argc, char **argv) { decaf::SecureBuffer ep, ep2(Point::SER_BYTES*2); printf("Micro-benchmarks:\n"); + decaf::SHAKE<128> shake1; + decaf::SHAKE<256> shake2; + decaf::SHA3<512> sha5; + unsigned char b1024[1024] = {1}; + for (Benchmark b("SHAKE128 1kiB", 30); b.iter(); ) { shake1 += decaf::TmpBuffer(b1024,1024); } + for (Benchmark b("SHAKE256 1kiB", 30); b.iter(); ) { shake2 += decaf::TmpBuffer(b1024,1024); } + for (Benchmark b("SHA3-512 1kiB", 30); b.iter(); ) { sha5 += decaf::TmpBuffer(b1024,1024); } for (Benchmark b("Scalar add", 1000); b.iter(); ) { s+=t; } for (Benchmark b("Scalar times", 100); b.iter(); ) { s*=t; } - for (Benchmark b("Scalar inv", 10); b.iter(); ) { s.inverse(); } + for (Benchmark b("Scalar inv", 1); b.iter(); ) { s.inverse(); } for (Benchmark b("Point add", 100); b.iter(); ) { p += q; } for (Benchmark b("Point double", 100); b.iter(); ) { p.double_in_place(); } for (Benchmark b("Point scalarmul"); b.iter(); ) { p * s; }