@@ -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; } | ||||