Browse Source

move eddsa.hxx to its own header. sha512.hxx; rework shake.hxx header; create prehash object. TODO: test prehash

master
Michael Hamburg 8 years ago
parent
commit
595855b434
11 changed files with 595 additions and 138 deletions
  1. +1
    -1
      Makefile
  2. +1
    -1
      src/gen_headers/template.py
  3. +1
    -98
      src/per_curve/decaf.tmpl.hxx
  4. +341
    -0
      src/per_curve/eddsa.tmpl.hxx
  5. +7
    -0
      src/public_include/decaf/eddsa.tmpl.hxx
  6. +103
    -0
      src/public_include/decaf/sha512.hxx
  7. +33
    -0
      src/public_include/decaf/shake.h
  8. +55
    -18
      src/public_include/decaf/shake.hxx
  9. +30
    -5
      src/shake.c
  10. +12
    -5
      test/bench_decaf.cxx
  11. +11
    -10
      test/test_decaf.cxx

+ 1
- 1
Makefile View File

@@ -170,7 +170,7 @@ LIBCOMPONENTS += $$(BUILD_OBJ)/$(1)/decaf.o $$(BUILD_OBJ)/$(1)/elligator.o $$(BU
PER_OBJ_DIRS += $$(BUILD_OBJ)/$(1)
GLOBAL_HEADERS_OF_$(1) = $(BUILD_INC)/decaf/decaf_$(3).h $(BUILD_INC)/decaf/decaf_$(3).hxx \
$(BUILD_INC)/decaf/crypto_$(3).h $(BUILD_INC)/decaf/crypto_$(3).hxx \
$(BUILD_INC)/decaf/eddsa_$(3).h
$(BUILD_INC)/decaf/eddsa_$(3).h $(BUILD_INC)/decaf/eddsa_$(3).hxx
HEADERS_OF_$(1) = $$(HEADERS_OF_$(2)) $$(GLOBAL_HEADERS_OF_$(1))
HEADERS += $$(GLOBAL_HEADERS_OF_$(1))



+ 1
- 1
src/gen_headers/template.py View File

@@ -50,7 +50,7 @@ def fillin(template,data):
if template[position] == '(': parens += 1
elif template[position] == ')': parens -= 1
position += 1
ret += str(eval(template[dollars+2:position-1],{'ser':ser,'msqrt':msqrt,'ceil_log2':ceil_log2},data))
ret += str(eval(template[dollars+2:position-1],{'re':re,'ser':ser,'msqrt':msqrt,'ceil_log2':ceil_log2},data))

author = "Mike Hamburg" # FUTURE
for name in args.files:


+ 1
- 98
src/per_curve/decaf.tmpl.hxx View File

@@ -21,7 +21,7 @@
#include <string.h> /* for memcpy */

#include <decaf/decaf_$(gf_bits).h>
#include <decaf/eddsa_$(gf_bits).h> /* TODO: move eddsa to another file? */
#include <decaf/eddsa_$(gf_bits).h>
#include <decaf/secure_buffer.hxx>
#include <string>
#include <sys/types.h>
@@ -679,103 +679,6 @@ public:
}
};

struct EdDSA { /* TODO: make into a utility class. Possibly move to another include file. */
public:
/** The size of a public key */
static const size_t PUBLIC_BYTES = $(C_NS)_EDDSA_PUBLIC_BYTES;
/** The size of a private key */
static const size_t PRIVATE_BYTES = $(C_NS)_EDDSA_PRIVATE_BYTES;
/** The size of a private key */
static const size_t SIGNATURE_BYTES = $(C_NS)_EDDSA_SIGNATURE_BYTES;
/** Do we support contexts for signatures? If not, they must always be NULL */
static const bool SUPPORTS_CONTEXTS = $(C_NS)_EDDSA_SUPPORTS_CONTEXTS;
static inline SecureBuffer generate_key (
const FixedBlock<PRIVATE_BYTES> &priv
) {
SecureBuffer out(PUBLIC_BYTES);
$(c_ns)_eddsa_derive_public_key(out.data(), priv.data());
return out;
}
static inline SecureBuffer sign (
const FixedBlock<PRIVATE_BYTES> &priv,
const FixedBlock<PUBLIC_BYTES> &pub,
const Block &message,
bool prehashed = false,
const Block &context = Block(NULL,0)
) throw(LengthException) {
if (context.size() > 255
|| (context.size() != 0 && !SUPPORTS_CONTEXTS)
) {
throw LengthException();
}
SecureBuffer out(SIGNATURE_BYTES);
$(c_ns)_eddsa_sign (
out.data(),
priv.data(),
pub.data(),
message.data(),
message.size(),
prehashed
#if $(C_NS)_EDDSA_SUPPORTS_CONTEXTS
, context.data(),
context.size()
#endif
);
return out;
}
static inline decaf_error_t WARN_UNUSED verify_noexcept (
const FixedBlock<SIGNATURE_BYTES> &sig,
const FixedBlock<PUBLIC_BYTES> &pub,
const Block &message,
bool prehashed = false,
const Block &context = Block(NULL,0)
) {
if (context.size() > 255
|| (context.size() != 0 && !SUPPORTS_CONTEXTS)
) {
return DECAF_FAILURE;
}
return $(c_ns)_eddsa_verify (
sig.data(),
pub.data(),
message.data(),
message.size(),
prehashed
#if $(C_NS)_EDDSA_SUPPORTS_CONTEXTS
, context.data(),
context.size()
#endif
);
}
static inline void verify (
const FixedBlock<SIGNATURE_BYTES> &sig,
const FixedBlock<PUBLIC_BYTES> &pub,
const Block &message,
bool prehashed = false,
const Block &context = Block(NULL,0)
) throw(LengthException,CryptoException) {
if (context.size() > 255
|| (context.size() != 0 && !SUPPORTS_CONTEXTS)
) {
throw LengthException();
}
if (DECAF_SUCCESS != verify_noexcept( sig, pub, message, prehashed, context )) {
throw CryptoException();
}
}
};

}; /* struct $(cxx_ns) */

/** @cond internal */


+ 341
- 0
src/per_curve/eddsa.tmpl.hxx View File

@@ -0,0 +1,341 @@

/*
* Example Decaf cyrpto routines, C++ wrapper.
* @warning These are merely examples, though they ought to be secure. But real
* protocols will decide differently on magic numbers, formats, which items to
* hash, etc.
* @warning Experimental! The names, parameter orders etc are likely to change.
*/

#include <decaf/decaf_$(gf_bits).hxx>
#include <decaf/eddsa_$(gf_bits).h>

#include <decaf/shake.hxx>
#include <decaf/sha512.hxx>

/** @cond internal */
#if __cplusplus >= 201103L
#define NOEXCEPT noexcept
#else
#define NOEXCEPT throw()
#endif
/** @endcond */

namespace decaf {

/** A public key for crypto over some Group */
template <typename Group> struct EdDSA;

/** A public key for crypto over $(name) */
template<> struct EdDSA<$(cxx_ns)> {

/** @cond internal */
class PrivateKey;
class PublicKey;
/** @endcond */

class Prehash : public $(re.sub(r"SHAKE(\d+)",r"SHAKE<\1>", eddsa_hash.upper())) {
public:
/** Do we support contexts for signatures? If not, they must always be NULL */
static const bool SUPPORTS_CONTEXTS = $(C_NS)_EDDSA_SUPPORTS_CONTEXTS;
private:
typedef $(re.sub(r"SHAKE(\d+)",r"SHAKE<\1>", eddsa_hash.upper())) Super;
SecureBuffer context_;
friend class PrivateKey;
friend class PublicKey;
void init() throw(LengthException) {
Super::reset();
if (context_.size() > 255
|| (context_.size() != 0 && !SUPPORTS_CONTEXTS)
) {
throw LengthException();
}
if (SUPPORTS_CONTEXTS) {
uint8_t dom[2] = {2, context_.size() };
update(dom,2);
update(context_);
}
}
public:
/** Number of output bytes in prehash */
static const size_t OUTPUT_BYTES = Super::DEFAULT_OUTPUT_BYTES;
/** Create the prehash */
Prehash(Block context = Block(NULL,0)) throw(LengthException) {
context_ = context;
init();
}

/** Reset this hash */
void reset() NOEXCEPT { init(); }
/** Output from this hash */
SecureBuffer final() throw(std::bad_alloc) {
SecureBuffer ret = Super::final(OUTPUT_BYTES);
reset();
return ret;
}
/** Output from this hash */
void final(Buffer &b) throw(LengthException) {
if (b.size() != OUTPUT_BYTES) throw LengthException();
Super::final(b);
reset();
}
};

class PrivateKey : public Serializable<PrivateKey> {
private:
/** @cond internal */
friend class PublicKey;
/** @endcond */
/** The pre-expansion form of the signing key. */
FixedArrayBuffer<$(C_NS)_EDDSA_PRIVATE_BYTES> priv_;
/** The post-expansion public key. */
FixedArrayBuffer<$(C_NS)_EDDSA_PUBLIC_BYTES> pub_;
public:
/** Underlying group */
typedef $(cxx_ns) Group;
/** Signature size. */
static const size_t SIG_BYTES = $(C_NS)_EDDSA_SIGNATURE_BYTES;
/** Serialization size. */
static const size_t SER_BYTES = $(C_NS)_EDDSA_PRIVATE_BYTES;
/** Do we support contexts for signatures? If not, they must always be NULL */
static const bool SUPPORTS_CONTEXTS = $(C_NS)_EDDSA_SUPPORTS_CONTEXTS;
/** Create but don't initialize */
inline explicit PrivateKey(const NOINIT&) NOEXCEPT : priv_((NOINIT())), pub_((NOINIT())) { }
/** Read a private key from a string */
inline explicit PrivateKey(const FixedBlock<SER_BYTES> &b) NOEXCEPT { *this = b; }
/** Copy constructor */
inline PrivateKey(const PrivateKey &k) NOEXCEPT { *this = k; }
/** Create at random */
inline explicit PrivateKey(Rng &r) NOEXCEPT : priv_(r) {
$(c_ns)_eddsa_derive_public_key(pub_.data(), priv_.data());
}
/** Assignment from string */
inline PrivateKey &operator=(const FixedBlock<SER_BYTES> &b) NOEXCEPT {
memcpy(priv_.data(),b.data(),b.size());
$(c_ns)_eddsa_derive_public_key(pub_.data(), priv_.data());
return *this;
}
/** Copy assignment */
inline PrivateKey &operator=(const PrivateKey &k) NOEXCEPT {
memcpy(priv_.data(),k.priv_.data(), priv_.size());
memcpy(pub_.data(),k.pub_.data(), pub_.size());
return *this;
}
/** Serialization size. */
inline size_t serSize() const NOEXCEPT { return SER_BYTES; }
/** Serialize into a buffer. */
inline void serialize_into(unsigned char *x) const NOEXCEPT {
memcpy(x,priv_.data(), priv_.size());
}
/** Return the corresponding public key */
inline PublicKey pub() const NOEXCEPT {
PublicKey pub(*this);
return pub;
}
/**
* Sign a message.
* @param [in] message The message to be signed.
* @param [in] prehashed If true, the message to be signed is already hashed.
* @param [in] context A context for the signature; must be at most 255 bytes;
* must be absent if SUPPORTS_CONTEXTS == false.
*
* @warning It is generally unsafe to use Ed25519 with both prehashed and non-prehashed messages.
*/
inline SecureBuffer sign (
const Block &message,
bool prehashed = false,
const Block &context = Block(NULL,0)
) const throw(LengthException, std::bad_alloc) {
if (context.size() > 255
|| (context.size() != 0 && !SUPPORTS_CONTEXTS)
) {
throw LengthException();
}
SecureBuffer out(SIG_BYTES);
$(c_ns)_eddsa_sign (
out.data(),
priv_.data(),
pub_.data(),
message.data(),
message.size(),
prehashed
#if $(C_NS)_EDDSA_SUPPORTS_CONTEXTS
, context.data(),
context.size()
#endif
);
return out;
}

/* Sign a prehash context, and reset the context */
inline SecureBuffer sign ( Prehash &ph ) const throw(std::bad_alloc) {
FixedArrayBuffer<Prehash::OUTPUT_BYTES> m;
ph.final(m);
return sign(m, true, ph.context_);
}
}; /* class PrivateKey */

class PublicKey : public Serializable<PublicKey> {
private:
/** @cond internal */
friend class PrivateKey;
/** @endcond */

public:
/** The pre-expansion form of the signature */
FixedArrayBuffer<$(C_NS)_EDDSA_PUBLIC_BYTES> pub_;
public:
/** Underlying group */
typedef $(cxx_ns) Group;
/** Signature size. */
static const size_t SIG_BYTES = $(C_NS)_EDDSA_SIGNATURE_BYTES;
/** Serialization size. */
static const size_t SER_BYTES = $(C_NS)_EDDSA_PRIVATE_BYTES;
/** Do we support contexts for signatures? If not, they must always be NULL */
static const bool SUPPORTS_CONTEXTS = $(C_NS)_EDDSA_SUPPORTS_CONTEXTS;
/** Create but don't initialize */
inline explicit PublicKey(const NOINIT&) NOEXCEPT : pub_((NOINIT())) { }
/** Read a private key from a string */
inline explicit PublicKey(const FixedBlock<SER_BYTES> &b) NOEXCEPT { *this = b; }
/** Copy constructor */
inline PublicKey(const PublicKey &k) NOEXCEPT { *this = k; }
/** Copy constructor */
inline explicit PublicKey(const PrivateKey &k) NOEXCEPT { *this = k; }

/** Assignment from string */
inline PublicKey &operator=(const FixedBlock<SER_BYTES> &b) NOEXCEPT {
memcpy(pub_.data(),b.data(),b.size());
return *this;
}

/** Assignment from private key */
inline PublicKey &operator=(const PublicKey &p) NOEXCEPT {
return *this = p.pub_;
}

/** Assignment from private key */
inline PublicKey &operator=(const PrivateKey &p) NOEXCEPT {
return *this = p.pub_;
}

/** Serialization size. */
inline size_t serSize() const NOEXCEPT { return SER_BYTES; }
/** Serialize into a buffer. */
inline void serialize_into(unsigned char *x) const NOEXCEPT {
memcpy(x,pub_.data(), pub_.size());
}
/** Verify a signature, returning DECAF_FAILURE if verification fails */
inline decaf_error_t WARN_UNUSED verify_noexcept (
const FixedBlock<SIG_BYTES> &sig,
const Block &message,
bool prehashed = false,
const Block &context = Block(NULL,0)
) const NOEXCEPT {
if (context.size() > 255
|| (context.size() != 0 && !SUPPORTS_CONTEXTS)
) {
return DECAF_FAILURE;
}
return $(c_ns)_eddsa_verify (
sig.data(),
pub_.data(),
message.data(),
message.size(),
prehashed
#if $(C_NS)_EDDSA_SUPPORTS_CONTEXTS
, context.data(),
context.size()
#endif
);
}
/** Verify a signature, throwing an exception if verification fails
* @param [in] sig The signature.
* @param [in] message The signed message.
* @param [in] prehashed If true, the message is already hashed.
* @param [in] context A context for the signature; must be at most 255 bytes;
* must be absent if SUPPORTS_CONTEXTS == false.
*
* @warning It is generally unsafe to use Ed25519 with both prehashed and non-prehashed messages.
*/
inline void verify (
const FixedBlock<SIG_BYTES> &sig,
const Block &message,
bool prehashed = false,
const Block &context = Block(NULL,0)
) const throw(LengthException,CryptoException) {
if (context.size() > 255
|| (context.size() != 0 && !SUPPORTS_CONTEXTS)
) {
throw LengthException();
}
if (DECAF_SUCCESS != verify_noexcept( sig, message, prehashed, context )) {
throw CryptoException();
}
}
/* Verify a prehash context, and reset the context */
inline decaf_error_t WARN_UNUSED verify_noexcept (
const FixedBlock<SIG_BYTES> &sig,
Prehash &ph
) const NOEXCEPT {
FixedArrayBuffer<Prehash::OUTPUT_BYTES> m;
ph.final(m);
return verify_noexcept(sig, m, true, ph.context_);
}
/* Verify a prehash context, and reset the context */
inline void verify (
const FixedBlock<SIG_BYTES> &sig,
Prehash &ph
) const throw(CryptoException) {
FixedArrayBuffer<Prehash::OUTPUT_BYTES> m;
ph.final(m);
verify(sig, m, true, ph.context_);
}
}; /* class PublicKey */

}; /* template<> struct EdDSA<$(cxx_ns)> */

#undef NOEXCEPT
} /* namespace decaf */

+ 7
- 0
src/public_include/decaf/eddsa.tmpl.hxx View File

@@ -0,0 +1,7 @@
/**
* EdDSA crypto routines, metaheader.
*/

$("\n".join([
"#include <decaf/eddsa_%s.hxx>" % g for g in sorted([c["bits"] for _,c in curve.iteritems()])
]))

+ 103
- 0
src/public_include/decaf/sha512.hxx View File

@@ -0,0 +1,103 @@
/**
* @file decaf/sha512.hxx
* @copyright
* Based on public domain code by Dan Bernstein \n
* Copyright (c) 2015 Cryptography Research, Inc. \n
* Released under the MIT License. See LICENSE.txt for license information.
* @author Mike Hamburg
* @brief SHA512 instance, C++ wrapper.
*/

#ifndef __DECAF_SHA512_HXX__
#define __DECAF_SHA512_HXX__

#include <decaf/secure_buffer.hxx>
#include <decaf/sha512.h>
#include <sys/types.h>

/** @cond internal */
#if __cplusplus >= 201103L
#define NOEXCEPT noexcept
#else
#define NOEXCEPT throw()
#endif
/** @endcond */

namespace decaf {
/** SHA512 wrapper function */
class SHA512 {
protected:
/** @cond internal */
/** The C-wrapper sponge state */
sha512_ctx_t sha;

public:
/** Number of bytes ouf output */
static const size_t OUTPUT_BYTES = 64;
/** Number of bytes of output */
static const size_t MAX_OUTPUT_BYTES = OUTPUT_BYTES;
/** Default number of bytes to output */
static const size_t DEFAULT_OUTPUT_BYTES = OUTPUT_BYTES;
/** Constructor */
inline SHA512() NOEXCEPT { sha512_init(sha); }
/** Add more data to running hash */
inline void update(const uint8_t *__restrict__ in, size_t len) NOEXCEPT { sha512_update(sha,in,len); }

/** Add more data to running hash, C++ version. */
inline void update(const Block &s) NOEXCEPT { update(s.data(),s.size()); }

/** Add more data, stream version. */
inline SHA512 &operator<<(const Block &s) { update(s); return *this; }

/** Same as <<. */
inline SHA512 &operator+=(const Block &s) { return *this << s; }
/** @brief Output bytes from the SHA context, and resets it. */
inline void final(Buffer b) throw(LengthException) {
if (b.size() > OUTPUT_BYTES) throw LengthException();
sha512_final(sha,b.data(),b.size());
}
/** Resets the SHA context */
inline void reset() NOEXCEPT { sha512_init(sha); }

/** @brief Output bytes from the sponge. */
inline SecureBuffer final(size_t len = OUTPUT_BYTES) throw(LengthException) {
if (len > OUTPUT_BYTES) throw LengthException();
SecureBuffer buffer(len);
sha512_final(sha,buffer.data(),len);
return buffer;
}

/** @brief Return the sponge's default output size. */
inline size_t default_output_size() const NOEXCEPT { return OUTPUT_BYTES; }

/** @brief Return the sponge's maximum output size. */
inline size_t max_output_size() const NOEXCEPT { return MAX_OUTPUT_BYTES; }

/** @brief Hash a message in one pass */
static inline SecureBuffer hash (
const Block &message,
size_t outlen = OUTPUT_BYTES
) throw(LengthException, std::bad_alloc) {
if (outlen > OUTPUT_BYTES) throw LengthException();
SecureBuffer buffer(outlen);
sha512_hash(buffer.data(),outlen,message.data(),message.size());
return buffer;
}

/** Destructor zeroizes state */
inline ~SHA512() NOEXCEPT { sha512_destroy(sha); }
};
} /* namespace decaf */

#undef NOEXCEPT

#endif /* __DECAF_SHA512_HXX__ */

+ 33
- 0
src/public_include/decaf/shake.h View File

@@ -76,6 +76,29 @@ void sha3_output (
size_t len
) API_VIS;

/**
* @brief Squeeze output data from a SHA3 or SHAKE hash context.
* This re-initializes the context to its starting parameters.
*
* @param [inout] sponge The context.
* @param [out] out The output data.
* @param [in] len The requested output data length in bytes.
*/
void sha3_final (
keccak_sponge_t sponge,
uint8_t * __restrict__ out,
size_t len
) API_VIS;

/**
* @brief Reset the sponge to the empty string.
*
* @param [inout] sponge The context.
*/
void sha3_reset (
keccak_sponge_t sponge
) API_VIS;

/**
* @brief Return the default output length of the sponge construction,
* for the purpose of C++ default operators.
@@ -86,6 +109,16 @@ size_t sponge_default_output_bytes (
const keccak_sponge_t sponge /**< [inout] The context. */
) API_VIS;

/**
* @brief Return the default output length of the sponge construction,
* for the purpose of C++ default operators.
*
* Returns n/8 for SHA3-n and SIZE_MAX for SHAKE-n.
*/
size_t sponge_max_output_bytes (
const keccak_sponge_t sponge /**< [inout] The context. */
) API_VIS;

/**
* @brief Destroy a SHA3 or SHAKE sponge context by overwriting it with 0.
* @param [out] sponge The context.


+ 55
- 18
src/public_include/decaf/shake.hxx View File

@@ -12,7 +12,7 @@
#define __DECAF_SHAKE_HXX__

#include <decaf/shake.h>
#include <decaf/secure_buffer.hxx>
#include <sys/types.h>

/** @cond internal */
@@ -43,28 +43,44 @@ protected:
public:
/** Add more data to running hash */
inline void update(const uint8_t *__restrict__ in, size_t len) { sha3_update(sp,in,len); }
inline void update(const uint8_t *__restrict__ in, size_t len) NOEXCEPT { sha3_update(sp,in,len); }

/** Add more data to running hash, C++ version. */
inline void update(const Block &s) { sha3_update(sp,s.data(),s.size()); }
inline void update(const Block &s) NOEXCEPT { sha3_update(sp,s.data(),s.size()); }
/** Add more data, stream version. */
inline KeccakHash &operator<<(const Block &s) { update(s); return *this; }
inline KeccakHash &operator<<(const Block &s) NOEXCEPT { update(s); return *this; }
/** Same as <<. */
inline KeccakHash &operator+=(const Block &s) { return *this << s; }
inline KeccakHash &operator+=(const Block &s) NOEXCEPT { return *this << s; }
/** @brief Output bytes from the sponge. */
inline SecureBuffer output(size_t len) throw(std::bad_alloc, LengthException) {
if (len > max_output_size()) throw LengthException();
SecureBuffer buffer(len);
sha3_output(sp,buffer.data(),len);
return buffer;
}
/** @brief Output bytes from the sponge. */
inline SecureBuffer final(size_t len) throw(std::bad_alloc, LengthException) {
if (len > max_output_size()) throw LengthException();
SecureBuffer buffer(len);
sha3_final(sp,buffer.data(),len);
return buffer;
}

/**
* @brief Output bytes from the sponge.
* @todo make this throw exceptions.
*/
inline void output(Buffer b) { sha3_output(sp,b.data(),b.size()); }
inline void output(Buffer b) throw(LengthException) {
sha3_output(sp,b.data(),b.size());
}
/** @brief Output bytes from the sponge. */
inline SecureBuffer output(size_t len) {
SecureBuffer buffer(len);
sha3_output(sp,buffer.data(),len);
return buffer;
/** @brief Output bytes from the sponge and reinitialize it. */
inline void final(Buffer b) throw(LengthException) {
sha3_final(sp,b.data(),b.size());
}
/** @brief Return the sponge's default output size. */
@@ -72,11 +88,24 @@ public:
return sponge_default_output_bytes(sp);
}
/** @brief Return the sponge's maximum output size. */
inline size_t max_output_size() const NOEXCEPT {
return sponge_max_output_bytes(sp);
}
/** Output the default number of bytes. */
inline SecureBuffer output() {
inline SecureBuffer output() throw(std::bad_alloc) {
return output(default_output_size());
}
/** Output the default number of bytes, and reset hash. */
inline SecureBuffer final() throw(std::bad_alloc) {
return final(default_output_size());
}

/** Reset the hash to the empty string */
inline void reset() NOEXCEPT { sha3_reset(sp); }
/** Destructor zeroizes state */
inline ~KeccakHash() NOEXCEPT { sponge_destroy(sp); }
};
@@ -91,12 +120,12 @@ public:
/** Number of bytes of output */
static const size_t MAX_OUTPUT_BYTES = bits/8;
/** Number of bytes of output */
static const size_t DEFAULT_OUTPUT_BYTES = bits/8;
/** Initializer */
inline SHA3() NOEXCEPT : KeccakHash(get_params()) {}

/** Reset the hash to the empty string */
inline void reset() NOEXCEPT { sponge_init(sp, get_params()); }

/** Hash bytes with this SHA3 instance.
* @throw LengthException if nbytes > MAX_OUTPUT_BYTES
*/
@@ -114,12 +143,20 @@ class SHAKE : public KeccakHash {
private:
/** Get the parameter template block for this hash */
static inline const struct kparams_s *get_params();
public:
/** Number of bytes of output */
#if __cplusplus >= 201103L
static const size_t MAX_OUTPUT_BYTES = SIZE_MAX;
#else
static const size_t MAX_OUTPUT_BYTES = (size_t)-1;
#endif

/** Default number of bytes to output */
static const size_t DEFAULT_OUTPUT_BYTES = bits/4;
/** Initializer */
inline SHAKE() NOEXCEPT : KeccakHash(get_params()) {}

/** Reset the hash to the empty string */
inline void reset() NOEXCEPT { sponge_init(sp, get_params()); }
/** Hash bytes with this SHAKE instance */
static inline SecureBuffer hash(const Block &b, size_t outlen) throw(std::bad_alloc) {


+ 30
- 5
src/shake.c View File

@@ -57,7 +57,7 @@ typedef union {
} kdomain_t[1];

typedef struct kparams_s {
uint8_t position, flags, rate, startRound, pad, ratePad, maxOut, client;
uint8_t position, flags, rate, startRound, pad, ratePad, maxOut, client; /* client = maxOutRemaining for sha3 */
} kparams_t[1];

typedef struct keccak_sponge_s {
@@ -174,8 +174,8 @@ void sha3_output (
assert(sponge->params->rate < sizeof(sponge->state));
if (sponge->params->maxOut != 0xFF) {
assert(sponge->params->maxOut >= len);
sponge->params->maxOut -= len;
assert(sponge->params->client >= len);
sponge->params->client -= len;
}
switch (sponge->params->flags) {
@@ -208,6 +208,22 @@ void sha3_output (
}
}

void sha3_final (
keccak_sponge_t sponge,
uint8_t * __restrict__ out,
size_t len
) {
sha3_output(sponge,out,len);
sha3_reset(sponge);
}

void sha3_reset (
keccak_sponge_t sponge
) {
sponge_init(sponge, sponge->params);
sponge->params->client = sponge->params->maxOut;
}

void sponge_destroy (keccak_sponge_t sponge) { decaf_bzero(sponge, sizeof(keccak_sponge_t)); }

void sponge_init (
@@ -216,6 +232,7 @@ void sponge_init (
) {
memset(sponge->state, 0, sizeof(sponge->state));
sponge->params[0] = params[0];
sponge->params->position = 0;
}

void sponge_hash (
@@ -234,11 +251,11 @@ void sponge_hash (

#define DEFSHAKE(n) \
const struct kparams_s SHAKE##n##_params_s = \
{ 0, FLAG_ABSORBING, 200-n/4, 0, 0x1f, 0x80, 0xFF, 0 };
{ 0, FLAG_ABSORBING, 200-n/4, 0, 0x1f, 0x80, 0xFF, 0xFF };
#define DEFSHA3(n) \
const struct kparams_s SHA3_##n##_params_s = \
{ 0, FLAG_ABSORBING, 200-n/4, 0, 0x06, 0x80, n/8, 0 };
{ 0, FLAG_ABSORBING, 200-n/4, 0, 0x06, 0x80, n/8, n/8 };

size_t sponge_default_output_bytes (
const keccak_sponge_t s
@@ -248,6 +265,14 @@ size_t sponge_default_output_bytes (
: ((200-s->params->rate)/2);
}

size_t sponge_max_output_bytes (
const keccak_sponge_t s
) {
return (s->params->maxOut == 0xFF)
? SIZE_MAX
: ((200-s->params->rate)/2);
}

DEFSHAKE(128)
DEFSHAKE(256)
DEFSHA3(224)


+ 12
- 5
test/bench_decaf.cxx View File

@@ -11,11 +11,13 @@

#include <decaf.hxx>
#include <decaf/shake.hxx>
#include <decaf/sha512.hxx>
#include <decaf/strobe.hxx>
#include <decaf/spongerng.hxx>
#include <decaf/crypto_255.h>
#include <decaf/crypto_448.h>
#include <decaf/crypto.hxx>
#include <decaf/eddsa.hxx>
#include <stdio.h>
#include <sys/time.h>
#include <assert.h>
@@ -295,11 +297,14 @@ static void cfrg() {
for (Benchmark b("RFC 7748 keygen"); b.iter(); ) { Group::DhLadder::generate_key(s1); }
for (Benchmark b("RFC 7748 shared secret"); b.iter(); ) { Group::DhLadder::shared_secret(base,s1); }

FixedArrayBuffer<Group::EdDSA::PRIVATE_BYTES> e1(rng);
SecureBuffer pk, sig;
for (Benchmark b("EdDSA keygen"); b.iter(); ) { pk = Group::EdDSA::generate_key(e1); }
for (Benchmark b("EdDSA sign"); b.iter(); ) { sig = Group::EdDSA::sign(e1,pk,Block(NULL,0)); }
for (Benchmark b("EdDSA verify"); b.iter(); ) { Group::EdDSA::verify(sig,pk,Block(NULL,0)); }
FixedArrayBuffer<EdDSA<Group>::PrivateKey::SER_BYTES> e1(rng);
typename EdDSA<Group>::PublicKey pub((NOINIT()));
typename EdDSA<Group>::PrivateKey priv((NOINIT()));
SecureBuffer sig;
for (Benchmark b("EdDSA keygen"); b.iter(); ) { priv = e1; }
for (Benchmark b("EdDSA sign"); b.iter(); ) { sig = priv.sign(Block(NULL,0)); }
pub = priv;
for (Benchmark b("EdDSA verify"); b.iter(); ) { pub.verify(sig,Block(NULL,0)); }
}

static void macro() {
@@ -408,11 +413,13 @@ int main(int argc, char **argv) {
SHAKE<128> shake1;
SHAKE<256> shake2;
SHA3<512> sha5;
SHA512 sha2;
Strobe strobe("example::bench",Strobe::CLIENT);
unsigned char b1024[1024] = {1};
for (Benchmark b("SHAKE128 1kiB", 30); b.iter(); ) { shake1 += Buffer(b1024,1024); }
for (Benchmark b("SHAKE256 1kiB", 30); b.iter(); ) { shake2 += Buffer(b1024,1024); }
for (Benchmark b("SHA3-512 1kiB", 30); b.iter(); ) { sha5 += Buffer(b1024,1024); }
for (Benchmark b("SHA512 1kiB", 30); b.iter(); ) { sha2 += Buffer(b1024,1024); }
strobe.dh_key(Buffer(b1024,1024));
strobe.respec(STROBE_128);
for (Benchmark b("STROBE128 1kiB", 10); b.iter(); ) {


+ 11
- 10
test/test_decaf.cxx View File

@@ -13,6 +13,7 @@
#include <decaf/spongerng.hxx>
#include <decaf/crypto.h>
#include <decaf/crypto.hxx>
#include <decaf/eddsa.hxx>
#include <stdio.h>

using namespace decaf;
@@ -56,7 +57,6 @@ template<typename Group> struct Tests {
typedef typename Group::Scalar Scalar;
typedef typename Group::Point Point;
typedef typename Group::DhLadder DhLadder;
typedef typename Group::EdDSA EdDSA;
typedef typename Group::Precomputed Precomputed;

static void print(const char *name, const Scalar &x) {
@@ -477,7 +477,8 @@ static void test_cfrg_vectors() {
/* EdDSA */
for (unsigned int t=0; eddsa_sk[t].size(); t++) {
SecureBuffer eddsa_pk2 = EdDSA::generate_key(eddsa_sk[t]);
typename EdDSA<Group>::PrivateKey priv(eddsa_sk[t]);
SecureBuffer eddsa_pk2 = priv.pub().serialize();
if (!memeq(SecureBuffer(eddsa_pk[t]), eddsa_pk2)) {
test.fail();
printf(" EdDSA PK vectors disagree.");
@@ -489,10 +490,10 @@ static void test_cfrg_vectors() {
printf("\n");
}
SecureBuffer sig;
if (EdDSA::SUPPORTS_CONTEXTS) {
sig = EdDSA::sign(eddsa_sk[t],eddsa_pk[t],eddsa_message[t],false,eddsa_context[t]);
if (priv.SUPPORTS_CONTEXTS) {
sig = priv.sign(eddsa_message[t],false,eddsa_context[t]);
} else {
sig = EdDSA::sign(eddsa_sk[t],eddsa_pk[t],eddsa_message[t]);
sig = priv.sign(eddsa_message[t]);
}

if (!memeq(SecureBuffer(eddsa_sig[t]),sig)) {
@@ -536,19 +537,19 @@ static void test_eddsa() {
for (int i=0; i<NTESTS && test.passing_now; i++) {
FixedArrayBuffer<EdDSA::PRIVATE_BYTES> priv(rng);
SecureBuffer pub = EdDSA::generate_key(priv);
typename EdDSA<Group>::PrivateKey priv(rng);
typename EdDSA<Group>::PublicKey pub(priv);
SecureBuffer message(i);
rng.read(message);
SecureBuffer context(EdDSA::SUPPORTS_CONTEXTS ? i%256 : 0);
SecureBuffer context(priv.SUPPORTS_CONTEXTS ? i%256 : 0);
rng.read(message);
SecureBuffer sig = EdDSA::sign(priv,pub,message,i%2,context);
SecureBuffer sig = priv.sign(message,i%2,context);
try {
EdDSA::verify(sig,pub,message,i%2,context);
pub.verify(sig,message,i%2,context);
} catch(CryptoException) {
test.fail();
printf(" Signature validation failed on sig %d\n", i);


Loading…
Cancel
Save