| @@ -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) | |||
| @@ -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; } | |||
| @@ -15,6 +15,8 @@ | |||
| #include <stdint.h> | |||
| #include <sys/types.h> | |||
| #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 | |||
| @@ -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<int bits> class SHA3 : public KeccakSponge { | |||
| template<int bits> 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<int bits> | |||
| class SHAKE : public KeccakSponge { | |||
| class SHAKE : public KeccakHash { | |||
| private: | |||
| /** Get the parameter template block for this hash */ | |||
| const struct kparams_s *get_params(); | |||
| @@ -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)-1), (x##ull)>>LBITS | |||
| @@ -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)-1), (x##ull)>>LBITS | |||
| @@ -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 && j<len; j++) state[j]^=in[j]; | |||
| if (out) memcpy(out, state, len); | |||
| sponge->params->position += len; | |||
| return; | |||
| } else { | |||
| if (in) { | |||
| for (j=0; j<cando; j++) state[j]^=in[j]; | |||
| in += cando; | |||
| } | |||
| if (out) { | |||
| memcpy(out, state, cando); | |||
| out += cando; | |||
| } | |||
| state[cando] ^= 0x1; | |||
| dokeccak(sponge); | |||
| len -= cando; | |||
| } | |||
| } | |||
| } | |||
| static void strobe_unduplex ( | |||
| 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 && j<len; j++) { | |||
| unsigned char c = in[j]; | |||
| out[j] = in[j] ^ state[j]; | |||
| state[j] = c; | |||
| } | |||
| sponge->params->position += len; | |||
| return; | |||
| } else { | |||
| for (j=0; in && j<cando; j++) { | |||
| unsigned char c = in[j]; | |||
| out[j] = in[j] ^ state[j]; | |||
| state[j] = c; | |||
| } | |||
| state[j] ^= 0x1; | |||
| dokeccak(sponge); | |||
| len -= cando; | |||
| } | |||
| } | |||
| } | |||
| enum { KEY, NONCE, AD, PLAINTEXT, CIPHERTEXT, TAGFORGET, DIVERSIFIER, PRNG, FORK, JOIN, RESPEC }; | |||
| #define CLIENT_TO_SERVER 0 | |||
| #define SERVER_TO_CLIENT 1 | |||
| struct strobe_control { | |||
| uint8_t next; | |||
| uint8_t bytes; | |||
| uint8_t flags; | |||
| } __attribute__((packed)); | |||
| static void strobe_control_word ( | |||
| strobe_t strobe, | |||
| const struct strobe_control *control | |||
| ) { | |||
| assert(strobe->sponge->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<len; i++) { | |||
| chain |= zero[i]; | |||
| } | |||
| return ((decaf_dword_t)chain-1)>>(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 */ | |||
| @@ -10,6 +10,7 @@ | |||
| */ | |||
| #include "decaf.hxx" | |||
| #include "shake.hxx" | |||
| #include "shake.h" | |||
| #include "decaf_crypto.h" | |||
| #include <stdio.h> | |||
| @@ -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; } | |||