| @@ -47,9 +47,11 @@ | |||||
| && !defined(DECAF_FORCE_32_BIT) | && !defined(DECAF_FORCE_32_BIT) | ||||
| #define DECAF_WORD_BITS 64 | #define DECAF_WORD_BITS 64 | ||||
| typedef uint64_t decaf_word_t, decaf_bool_t; | typedef uint64_t decaf_word_t, decaf_bool_t; | ||||
| typedef __uint128_t decaf_dword_t; | |||||
| #else | #else | ||||
| #define DECAF_WORD_BITS 32 | #define DECAF_WORD_BITS 32 | ||||
| typedef uint32_t decaf_word_t, decaf_bool_t; | typedef uint32_t decaf_word_t, decaf_bool_t; | ||||
| typedef uint64_t decaf_dword_t; | |||||
| #endif | #endif | ||||
| #define DECAF_448_LIMBS (512/DECAF_WORD_BITS) | #define DECAF_448_LIMBS (512/DECAF_WORD_BITS) | ||||
| @@ -281,13 +281,7 @@ public: | |||||
| inline Scalar(const Scalar &x) NOEXCEPT { *this = x; } | inline Scalar(const Scalar &x) NOEXCEPT { *this = x; } | ||||
| /** @brief Construct from arbitrary-length little-endian byte sequence. */ | /** @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. */ | /** @brief Assignment. */ | ||||
| inline Scalar& operator=(const Scalar &x) NOEXCEPT { decaf_448_scalar_copy(s,x.s); return *this; } | inline Scalar& operator=(const Scalar &x) NOEXCEPT { decaf_448_scalar_copy(s,x.s); return *this; } | ||||
| @@ -15,6 +15,8 @@ | |||||
| #include <stdint.h> | #include <stdint.h> | ||||
| #include <sys/types.h> | #include <sys/types.h> | ||||
| #include "decaf.h" /* TODO: orly? */ | |||||
| /* TODO: unify with other headers (maybe all into one??); add nonnull attributes */ | /* TODO: unify with other headers (maybe all into one??); add nonnull attributes */ | ||||
| /** @cond internal */ | /** @cond internal */ | ||||
| #define API_VIS __attribute__((visibility("default"))) | #define API_VIS __attribute__((visibility("default"))) | ||||
| @@ -30,8 +32,14 @@ | |||||
| /** @endcond */ | /** @endcond */ | ||||
| } keccak_sponge_t[1]; | } keccak_sponge_t[1]; | ||||
| struct kparams_s; | struct kparams_s; | ||||
| typedef struct { uint64_t opaque; } strobe_params_t[1]; | |||||
| #endif | #endif | ||||
| typedef struct strobe_s { | |||||
| keccak_sponge_t sponge; | |||||
| strobe_params_t params; | |||||
| } strobe_s, strobe_t[1]; | |||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||
| extern "C" { | extern "C" { | ||||
| #endif | #endif | ||||
| @@ -243,6 +251,84 @@ void spongerng_stir ( | |||||
| size_t len | size_t len | ||||
| ) API_VIS; | ) 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 | #ifdef __cplusplus | ||||
| } /* extern "C" */ | } /* extern "C" */ | ||||
| #endif | #endif | ||||
| @@ -75,15 +75,19 @@ public: | |||||
| * @brief Output bytes from the sponge. | * @brief Output bytes from the sponge. | ||||
| * @todo make this throw exceptions. | * @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. */ | /** @brief Output bytes from the sponge. */ | ||||
| inline SecureBuffer output(size_t len) { | inline SecureBuffer output(size_t len) { | ||||
| SecureBuffer buffer(len); | |||||
| SecureBuffer buffer(len); | |||||
| sha3_output(sp,buffer,len); | sha3_output(sp,buffer,len); | ||||
| return buffer; | |||||
| return buffer; | |||||
| } | } | ||||
| /** @brief Return the sponge's default output size. */ | /** @brief Return the sponge's default output size. */ | ||||
| @@ -98,7 +102,7 @@ public: | |||||
| }; | }; | ||||
| /** Fixed-output-length SHA3 */ | /** Fixed-output-length SHA3 */ | ||||
| template<int bits> class SHA3 : public KeccakSponge { | |||||
| template<int bits> class SHA3 : public KeccakHash { | |||||
| private: | private: | ||||
| /** Get the parameter template block for this hash */ | /** Get the parameter template block for this hash */ | ||||
| const struct kparams_s *get_params(); | const struct kparams_s *get_params(); | ||||
| @@ -109,7 +113,7 @@ public: | |||||
| /** Variable-output-length SHAKE */ | /** Variable-output-length SHAKE */ | ||||
| template<int bits> | template<int bits> | ||||
| class SHAKE : public KeccakSponge { | |||||
| class SHAKE : public KeccakHash { | |||||
| private: | private: | ||||
| /** Get the parameter template block for this hash */ | /** Get the parameter template block for this hash */ | ||||
| const struct kparams_s *get_params(); | const struct kparams_s *get_params(); | ||||
| @@ -17,12 +17,10 @@ | |||||
| #if WBITS == 64 | #if WBITS == 64 | ||||
| #define LBITS 56 | #define LBITS 56 | ||||
| typedef __uint128_t decaf_dword_t; | |||||
| typedef __int128_t decaf_sdword_t; | typedef __int128_t decaf_sdword_t; | ||||
| #define LIMB(x) (x##ull) | #define LIMB(x) (x##ull) | ||||
| #define SC_LIMB(x) (x##ull) | #define SC_LIMB(x) (x##ull) | ||||
| #elif WBITS == 32 | #elif WBITS == 32 | ||||
| typedef uint64_t decaf_dword_t; | |||||
| typedef int64_t decaf_sdword_t; | typedef int64_t decaf_sdword_t; | ||||
| #define LBITS 28 | #define LBITS 28 | ||||
| #define LIMB(x) (x##ull)&((1ull<<LBITS)-1), (x##ull)>>LBITS | #define LIMB(x) (x##ull)&((1ull<<LBITS)-1), (x##ull)>>LBITS | ||||
| @@ -18,12 +18,10 @@ | |||||
| #if WBITS == 64 | #if WBITS == 64 | ||||
| #define LBITS 56 | #define LBITS 56 | ||||
| typedef __uint128_t decaf_dword_t; | |||||
| typedef __int128_t decaf_sdword_t; | typedef __int128_t decaf_sdword_t; | ||||
| #define LIMB(x) (x##ull) | #define LIMB(x) (x##ull) | ||||
| #define SC_LIMB(x) (x##ull) | #define SC_LIMB(x) (x##ull) | ||||
| #elif WBITS == 32 | #elif WBITS == 32 | ||||
| typedef uint64_t decaf_dword_t; | |||||
| typedef int64_t decaf_sdword_t; | typedef int64_t decaf_sdword_t; | ||||
| #define LBITS 28 | #define LBITS 28 | ||||
| #define LIMB(x) (x##ull)&((1ull<<LBITS)-1), (x##ull)>>LBITS | #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, _; | uint8_t position, flags, rate, startRound, pad, ratePad, maxOut, _; | ||||
| } kparams_t[1]; | } kparams_t[1]; | ||||
| typedef struct strobe_params_s { | |||||
| uint8_t client, _[7]; | |||||
| } strobe_params_t[1]; | |||||
| typedef struct keccak_sponge_s { | typedef struct keccak_sponge_s { | ||||
| kdomain_t state; | kdomain_t state; | ||||
| kparams_t params; | kparams_t params; | ||||
| @@ -68,6 +72,7 @@ typedef struct keccak_sponge_s { | |||||
| #define INTERNAL_SPONGE_STRUCT 1 | #define INTERNAL_SPONGE_STRUCT 1 | ||||
| #include "shake.h" | #include "shake.h" | ||||
| #include "decaf.h" | |||||
| #define FLAG_ABSORBING 'A' | #define FLAG_ABSORBING 'A' | ||||
| #define FLAG_SQUEEZING 'Z' | #define FLAG_SQUEEZING 'Z' | ||||
| @@ -446,4 +451,212 @@ int spongerng_init_from_dev_urandom ( | |||||
| return spongerng_init_from_file(sponge, "/dev/urandom", 64, 0); | 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 */ | /* TODO: Keyak instances, etc */ | ||||
| @@ -10,6 +10,7 @@ | |||||
| */ | */ | ||||
| #include "decaf.hxx" | #include "decaf.hxx" | ||||
| #include "shake.hxx" | |||||
| #include "shake.h" | #include "shake.h" | ||||
| #include "decaf_crypto.h" | #include "decaf_crypto.h" | ||||
| #include <stdio.h> | #include <stdio.h> | ||||
| @@ -134,9 +135,16 @@ int main(int argc, char **argv) { | |||||
| decaf::SecureBuffer ep, ep2(Point::SER_BYTES*2); | decaf::SecureBuffer ep, ep2(Point::SER_BYTES*2); | ||||
| printf("Micro-benchmarks:\n"); | 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 add", 1000); b.iter(); ) { s+=t; } | ||||
| for (Benchmark b("Scalar times", 100); 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 add", 100); b.iter(); ) { p += q; } | ||||
| for (Benchmark b("Point double", 100); b.iter(); ) { p.double_in_place(); } | for (Benchmark b("Point double", 100); b.iter(); ) { p.double_in_place(); } | ||||
| for (Benchmark b("Point scalarmul"); b.iter(); ) { p * s; } | for (Benchmark b("Point scalarmul"); b.iter(); ) { p * s; } | ||||