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