Browse Source

working on breaking up include files

master
Michael Hamburg 9 years ago
parent
commit
db0a12de2a
8 changed files with 500 additions and 379 deletions
  1. +59
    -1
      include/decaf.h
  2. +22
    -57
      include/decaf_255.h
  3. +58
    -207
      include/decaf_255.hxx
  4. +2
    -53
      include/decaf_448.h
  5. +302
    -0
      include/secure_buffer.hxx
  6. +8
    -44
      include/shake.hxx
  7. +22
    -11
      src/decaf_fast.c
  8. +27
    -6
      test/test_decaf.cxx

+ 59
- 1
include/decaf.h View File

@@ -2,7 +2,65 @@
#ifndef __DECAF_H__
#define __DECAF_H__ 1

#include "decaf_255.h" // MAGIC
#include <stdint.h>
#include <sys/types.h>

/* Goldilocks' build flags default to hidden and stripping executables. */
/** @cond internal */
#if defined(DOXYGEN) && !defined(__attribute__)
#define __attribute__((x))
#endif
#define API_VIS __attribute__((visibility("default")))
#define NOINLINE __attribute__((noinline))
#define WARN_UNUSED __attribute__((warn_unused_result))
#define NONNULL1 __attribute__((nonnull(1)))
#define NONNULL2 __attribute__((nonnull(1,2)))
#define NONNULL3 __attribute__((nonnull(1,2,3)))
#define NONNULL4 __attribute__((nonnull(1,2,3,4)))
#define NONNULL5 __attribute__((nonnull(1,2,3,4,5)))
/** @endcond */

/* Internal word types */
#if (defined(__ILP64__) || defined(__amd64__) || defined(__x86_64__) || (((__UINT_FAST32_MAX__)>>30)>>30)) \
&& !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


#ifdef __cplusplus
extern "C" {
#endif
/** DECAF_TRUE = -1 so that DECAF_TRUE & x = x */
static const decaf_bool_t DECAF_TRUE = -(decaf_bool_t)1, DECAF_FALSE = 0;

/** NB Success is -1, failure is 0. TODO: see if people would rather the reverse. */
static const decaf_bool_t DECAF_SUCCESS = -(decaf_bool_t)1 /*DECAF_TRUE*/,
DECAF_FAILURE = 0 /*DECAF_FALSE*/;
#include "decaf_255.h"
#include "decaf_448.h"


#ifdef __cplusplus
}
#endif


#undef API_VIS
#undef WARN_UNUSED
#undef NOINLINE
#undef NONNULL1
#undef NONNULL2
#undef NONNULL3
#undef NONNULL4
#undef NONNULL5

#endif /* __DECAF_H__ */


+ 22
- 57
include/decaf_255.h View File

@@ -25,33 +25,8 @@
#ifndef __DECAF_255_H__
#define __DECAF_255_H__ 1

#include <stdint.h>
#include <sys/types.h>

/* Goldilocks' build flags default to hidden and stripping executables. */
/** @cond internal */
#if defined(DOXYGEN) && !defined(__attribute__)
#define __attribute__((x))
#endif
#define API_VIS __attribute__((visibility("default")))
#define NOINLINE __attribute__((noinline))
#define WARN_UNUSED __attribute__((warn_unused_result))
#define NONNULL1 __attribute__((nonnull(1)))
#define NONNULL2 __attribute__((nonnull(1,2)))
#define NONNULL3 __attribute__((nonnull(1,2,3)))
#define NONNULL4 __attribute__((nonnull(1,2,3,4)))
#define NONNULL5 __attribute__((nonnull(1,2,3,4,5)))

/* Internal word types */
#if (defined(__ILP64__) || defined(__amd64__) || defined(__x86_64__) || (((__UINT_FAST32_MAX__)>>30)>>30)) \
&& !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;
#ifndef __DECAF_H__
#error "include <decaf.h>, not <decaf_255.h>."
#endif

#define DECAF_255_LIMBS (320/DECAF_WORD_BITS)
@@ -59,9 +34,9 @@ typedef uint64_t decaf_dword_t;
#define DECAF_255_SCALAR_LIMBS (256/DECAF_WORD_BITS)

/** Galois field element internal structure */
typedef struct gf_s {
typedef struct gf_255_s {
decaf_word_t limb[DECAF_255_LIMBS];
} gf_s, gf[1];
} gf_255_s, gf_255_t[1];
/** @endcond */

/** Number of bytes in a serialized point. */
@@ -71,7 +46,7 @@ typedef struct gf_s {
#define DECAF_255_SCALAR_BYTES 32

/** Twisted Edwards (-1,d-1) extended homogeneous coordinates */
typedef struct decaf_255_point_s { /**@cond internal*/gf x,y,z,t;/**@endcond*/ } decaf_255_point_t[1];
typedef struct decaf_255_point_s { /**@cond internal*/gf_255_t x,y,z,t;/**@endcond*/ } decaf_255_point_t[1];

/** Precomputed table based on a point. Can be trivial implementation. */
struct decaf_255_precomputed_s;
@@ -89,13 +64,6 @@ typedef struct decaf_255_scalar_s {
/** @endcond */
} decaf_255_scalar_t[1];

/** DECAF_TRUE = -1 so that DECAF_TRUE & x = x */
static const decaf_bool_t DECAF_TRUE = -(decaf_bool_t)1, DECAF_FALSE = 0;

/** NB Success is -1, failure is 0. TODO: see if people would rather the reverse. */
static const decaf_bool_t DECAF_SUCCESS = -(decaf_bool_t)1 /*DECAF_TRUE*/,
DECAF_FAILURE = 0 /*DECAF_FALSE*/;

/** A scalar equal to 1. */
extern const decaf_255_scalar_t decaf_255_scalar_one API_VIS;

@@ -115,10 +83,6 @@ extern const decaf_255_point_t decaf_255_point_base API_VIS;
/** Precomputed table for the base point on the curve. */
extern const struct decaf_255_precomputed_s *decaf_255_precomputed_base API_VIS;

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Read a scalar from wire format or from bytes.
*
@@ -481,7 +445,8 @@ decaf_bool_t decaf_255_point_valid (
) API_VIS WARN_UNUSED NONNULL1 NOINLINE;

/**
* @brief 2-torque a point, for debugging purposes.
* @brief Torque a point, for debugging purposes. The output
* will be equal to the input.
*
* @param [out] q The point to torque.
* @param [in] p The point to torque.
@@ -491,6 +456,21 @@ void decaf_255_point_debugging_torque (
const decaf_255_point_t p
) API_VIS NONNULL2 NOINLINE;

/**
* @brief Projectively scale a point, for debugging purposes.
* The output will be equal to the input, and will be valid
* even if the factor is zero.
*
* @param [out] q The point to scale.
* @param [in] p The point to scale.
* @param [in] factor Serialized GF factor to scale.
*/
void decaf_255_point_debugging_pscale (
decaf_255_point_t q,
const decaf_255_point_t p,
const unsigned char factor[DECAF_255_SER_BYTES]
) API_VIS NONNULL2 NOINLINE;

/**
* @brief Almost-Elligator-like hash to curve.
*
@@ -624,19 +604,4 @@ void decaf_255_precomputed_destroy (
decaf_255_precomputed_s *pre
) NONNULL1 API_VIS;

/* TODO: functions to invert point_from_hash?? */

#undef API_VIS
#undef WARN_UNUSED
#undef NOINLINE
#undef NONNULL1
#undef NONNULL2
#undef NONNULL3
#undef NONNULL4
#undef NONNULL5

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* __DECAF_255_H__ */

+ 58
- 207
include/decaf_255.hxx View File

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

#include "decaf.h"
#include "secure_buffer.hxx"
#include <string>
#include <sys/types.h>
#include <limits.h>
@@ -39,209 +40,18 @@
#if __cplusplus >= 201103L
#define NOEXCEPT noexcept
#define EXPLICIT_CON explicit
#define GET_DATA(str) ((const unsigned char *)&(str)[0])
#define FINAL final
#define DELETE = delete
#else
#define NOEXCEPT throw()
#define EXPLICIT_CON
#define GET_DATA(str) ((const unsigned char *)((str).data()))
#define FINAL
#define DELETE
#endif
/** @endcond */

namespace decaf {

/** @brief An exception for when crypto (ie point decode) has failed. */
class CryptoException : public std::exception {
public:
/** @return "CryptoException" */
virtual const char * what() const NOEXCEPT { return "CryptoException"; }
};

/** @brief An exception for when crypto (ie point decode) has failed. */
class LengthException : public std::exception {
public:
/** @return "CryptoException" */
virtual const char * what() const NOEXCEPT { return "LengthException"; }
};

/**
* Securely erase contents of memory.
*/
static inline void really_bzero(void *data, size_t size) { decaf_bzero(data,size); }

/** Block object */
class Block {
protected:
unsigned char *data_;
size_t size_;

public:
/** Empty init */
inline Block() NOEXCEPT : data_(NULL), size_(0) {}
/** Init from C string */
inline Block(const char *data) NOEXCEPT : data_((unsigned char *)data), size_(strlen(data)) {}

/** Unowned init */
inline Block(const unsigned char *data, size_t size) NOEXCEPT : data_((unsigned char *)data), size_(size) {}
/** Block from std::string */
inline Block(const std::string &s) : data_((unsigned char *)GET_DATA(s)), size_(s.size()) {}

/** Get const data */
inline const unsigned char *data() const NOEXCEPT { return data_; }

/** Get the size */
inline size_t size() const NOEXCEPT { return size_; }

/** Autocast to const unsigned char * */
inline operator const unsigned char*() const NOEXCEPT { return data_; }

/** Convert to C++ string */
inline std::string get_string() const {
return std::string((const char *)data_,size_);
}

/** Slice the buffer*/
inline Block slice(size_t off, size_t length) const throw(LengthException) {
if (off > size() || length > size() - off)
throw LengthException();
return Block(data()+off, length);
}
/* Content-wise comparison; constant-time if they are the same length.
* FIXME: is it wise to have a content-wise compare on objects that may be mutable?
*/
inline decaf_bool_t operator==(const Block &b) const NOEXCEPT {
return ~(*this != b);
}
inline decaf_bool_t operator!=(const Block &b) const NOEXCEPT {
if (b.size() != size()) return true;
return ~decaf_memeq(b,*this,size());
}

/** Virtual destructor for SecureBlock. TODO: probably means vtable? Make bool? */
inline virtual ~Block() {};
};

class TmpBuffer;

class Buffer : public Block {
public:
/** Null init */
inline Buffer() NOEXCEPT : Block() {}

/** Unowned init */
inline Buffer(unsigned char *data, size_t size) NOEXCEPT : Block(data,size) {}

/** Get unconst data */
inline unsigned char *data() NOEXCEPT { return data_; }

/** Get const data */
inline const unsigned char *data() const NOEXCEPT { return data_; }

/** Autocast to const unsigned char * */
inline operator const unsigned char*() const NOEXCEPT { return data_; }

/** Autocast to unsigned char */
inline operator unsigned char*() NOEXCEPT { return data_; }

/** Slice the buffer*/
inline TmpBuffer slice(size_t off, size_t length) throw(LengthException);
};

class TmpBuffer : public Buffer {
public:
/** Unowned init */
inline TmpBuffer(unsigned char *data, size_t size) NOEXCEPT : Buffer(data,size) {}
};

TmpBuffer Buffer::slice(size_t off, size_t length) throw(LengthException) {
if (off > size() || length > size() - off) throw LengthException();
return TmpBuffer(data()+off, length);
}

/** A self-erasing block of data */
class SecureBuffer : public Buffer {
public:
/** Null secure block */
inline SecureBuffer() NOEXCEPT : Buffer() {}

/** Construct empty from size */
inline SecureBuffer(size_t size) {
data_ = new unsigned char[size_ = size];
memset(data_,0,size);
}

/** Construct from data */
inline SecureBuffer(const unsigned char *data, size_t size){
data_ = new unsigned char[size_ = size];
memcpy(data_, data, size);
}

/** Copy constructor */
inline SecureBuffer(const Block &copy) : Buffer() { *this = copy; }

/** Copy-assign constructor */
inline SecureBuffer& operator=(const Block &copy) throw(std::bad_alloc) {
if (&copy == this) return *this;
clear();
data_ = new unsigned char[size_ = copy.size()];
memcpy(data_,copy.data(),size_);
return *this;
}

/** Copy-assign constructor */
inline SecureBuffer& operator=(const SecureBuffer &copy) throw(std::bad_alloc) {
if (&copy == this) return *this;
clear();
data_ = new unsigned char[size_ = copy.size()];
memcpy(data_,copy.data(),size_);
return *this;
}

/** Destructor erases data */
~SecureBuffer() NOEXCEPT { clear(); }

/** Clear data */
inline void clear() NOEXCEPT {
if (data_ == NULL) return;
really_bzero(data_,size_);
delete[] data_;
data_ = NULL;
size_ = 0;
}

#if __cplusplus >= 201103L
/** Move constructor */
inline SecureBuffer(SecureBuffer &&move) { *this = move; }

/** Move non-constructor */
inline SecureBuffer(Block &&move) { *this = (Block &)move; }

/** Move-assign constructor. TODO: check that this actually gets used.*/
inline SecureBuffer& operator=(SecureBuffer &&move) {
clear();
data_ = move.data_; move.data_ = NULL;
size_ = move.size_; move.size_ = 0;
return *this;
}

/** C++11-only explicit cast */
inline explicit operator std::string() const { return get_string(); }
#endif
};


/** @brief Passed to constructors to avoid (conservative) initialization */
struct NOINIT {};

/**@cond internal*/
/** Forward-declare sponge RNG object */
class SpongeRng;
/**@endcond*/


/**
* @brief Ed255-Goldilocks/Decaf instantiation of group.
*/
@@ -274,7 +84,10 @@ public:
inline Scalar(const int w) NOEXCEPT { *this = w; }
/** @brief Construct from RNG */
inline explicit Scalar(SpongeRng &rng) NOEXCEPT;
inline explicit Scalar(Rng &rng) NOEXCEPT {
StackBuffer<SER_BYTES> sb(rng);
*this = sb;
}
/** @brief Construct from decaf_scalar_t object. */
inline Scalar(const decaf_255_scalar_t &t = decaf_255_scalar_zero) NOEXCEPT { decaf_255_scalar_copy(s,t); }
@@ -299,7 +112,7 @@ public:
return *this;
}
/** Destructor securely erases the scalar. */
/** Destructor securely zeorizes the scalar. */
inline ~Scalar() NOEXCEPT { decaf_255_scalar_destroy(s); }
/** @brief Assign from arbitrary-length little-endian byte sequence in a Block. */
@@ -414,16 +227,24 @@ public:
inline Point(const decaf_255_point_t &q = decaf_255_point_identity) NOEXCEPT { decaf_255_point_copy(p,q); }
/** @brief Copy constructor. */
inline Point(const Point &q) NOEXCEPT { decaf_255_point_copy(p,q.p); }
inline Point(const Point &q) NOEXCEPT { *this = q; }
/** @brief Assignment. */
inline Point& operator=(const Point &q) NOEXCEPT { decaf_255_point_copy(p,q.p); return *this; }
/** @brief Destructor securely erases the point. */
/** @brief Destructor securely zeorizes the point. */
inline ~Point() NOEXCEPT { decaf_255_point_destroy(p); }
/** @brief Construct from RNG */
inline explicit Point(SpongeRng &rng, bool uniform = true) NOEXCEPT;
inline explicit Point(Rng &rng, bool uniform = true) NOEXCEPT {
if (uniform) {
StackBuffer<2*HASH_BYTES> b(rng);
set_to_hash(b);
} else {
StackBuffer<HASH_BYTES> b(rng);
set_to_hash(b);
}
}
/**
* @brief Initialize from C++ fixed-length byte string.
@@ -591,11 +412,30 @@ public:
Point r((NOINIT())); decaf_255_base_double_scalarmul_non_secret(r.p,s_base.s,p,s.s); return r;
}
inline Point& debugging_torque_in_place() {
decaf_255_point_debugging_torque(p,p);
return *this;
/** @brief Return a point equal to *this, whose internal data is rotated by a torsion element. */
inline Point debugging_torque() const NOEXCEPT {
Point q;
decaf_255_point_debugging_torque(q.p,p);
return q;
}
/** @brief Return a point equal to *this, whose internal data has a modified representation. */
inline Point debugging_pscale(const uint8_t factor[/*SER_BYTES*/]) const NOEXCEPT {
Point q;
decaf_255_point_debugging_pscale(q.p,p,factor);
return q;
}
/** @brief Return a point equal to *this, whose internal data has a randomized representation. */
inline Point debugging_pscale(Rng &r) const NOEXCEPT {
StackBuffer<SER_BYTES> sb(r);
return debugging_pscale(sb);
}
/**
* Modify buffer so that Point::from_hash(Buffer) == *this, and return true;
* or leave buf unmodified and return false.
*/
inline bool invert_elligator (
Buffer &buf, uint16_t hint
) const NOEXCEPT {
@@ -611,13 +451,24 @@ public:
if (buf.size() < HASH_BYTES) {
ret &= decaf_memeq(&buf2[buf.size()], &buf2[HASH_BYTES], HASH_BYTES - buf.size());
}
memcpy(buf,buf2,(buf.size() < HASH_BYTES) ? buf.size() : HASH_BYTES);
if (ret) {
/* TODO: make this constant time?? */
memcpy(buf,buf2,(buf.size() < HASH_BYTES) ? buf.size() : HASH_BYTES);
}
decaf_bzero(buf2,sizeof(buf2));
return !!ret;
}
/** @brief Steganographically encode this */
inline SecureBuffer steg_encode(SpongeRng &rng) const NOEXCEPT;
inline SecureBuffer steg_encode(Rng &rng) const throw(std::bad_alloc) {
SecureBuffer out(STEG_BYTES);
bool done;
do {
rng.read(out.slice(HASH_BYTES-1,STEG_BYTES-HASH_BYTES+1));
done = invert_elligator(out, out[HASH_BYTES-1]);
} while (!done);
return out;
}
/** @brief Return the base point */
static inline const Point base() NOEXCEPT { return Point(decaf_255_point_base); }
@@ -661,7 +512,7 @@ private:
inline const decaf_255_precomputed_s *get() const NOEXCEPT { return isMine ? ours.mine : ours.yours; }
/** @endcond */
public:
/** Destructor securely erases the memory. */
/** Destructor securely zeorizes the memory. */
inline ~Precomputed() NOEXCEPT { clear(); }
/**
@@ -744,7 +595,7 @@ public:

#undef NOEXCEPT
#undef EXPLICIT_CON
#undef GET_DATA
#undef FINAL
} /* namespace decaf */

#endif /* __DECAF_255_HXX__ */

+ 2
- 53
include/decaf_448.h View File

@@ -25,33 +25,8 @@
#ifndef __DECAF_448_H__
#define __DECAF_448_H__ 1

#include <stdint.h>
#include <sys/types.h>

/* Goldilocks' build flags default to hidden and stripping executables. */
/** @cond internal */
#if defined(DOXYGEN) && !defined(__attribute__)
#define __attribute__((x))
#endif
#define API_VIS __attribute__((visibility("default")))
#define NOINLINE __attribute__((noinline))
#define WARN_UNUSED __attribute__((warn_unused_result))
#define NONNULL1 __attribute__((nonnull(1)))
#define NONNULL2 __attribute__((nonnull(1,2)))
#define NONNULL3 __attribute__((nonnull(1,2,3)))
#define NONNULL4 __attribute__((nonnull(1,2,3,4)))
#define NONNULL5 __attribute__((nonnull(1,2,3,4,5)))

/* Internal word types */
#if (defined(__ILP64__) || defined(__amd64__) || defined(__x86_64__) || (((__UINT_FAST32_MAX__)>>30)>>30)) \
&& !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;
#ifndef __DECAF_H__
#error "include <decaf.h>, not <decaf_448.h>."
#endif

#define DECAF_448_LIMBS (512/DECAF_WORD_BITS)
@@ -89,13 +64,6 @@ typedef struct decaf_448_scalar_s {
/** @endcond */
} decaf_448_scalar_t[1];

/** DECAF_TRUE = -1 so that DECAF_TRUE & x = x */
static const decaf_bool_t DECAF_TRUE = -(decaf_bool_t)1, DECAF_FALSE = 0;

/** NB Success is -1, failure is 0. TODO: see if people would rather the reverse. */
static const decaf_bool_t DECAF_SUCCESS = -(decaf_bool_t)1 /*DECAF_TRUE*/,
DECAF_FAILURE = 0 /*DECAF_FALSE*/;

/** A scalar equal to 1. */
extern const decaf_448_scalar_t decaf_448_scalar_one API_VIS;

@@ -115,10 +83,6 @@ extern const decaf_448_point_t decaf_448_point_base API_VIS;
/** Precomputed table for the base point on the curve. */
extern const struct decaf_448_precomputed_s *decaf_448_precomputed_base API_VIS;

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Read a scalar from wire format or from bytes.
*
@@ -633,19 +597,4 @@ void decaf_448_precomputed_destroy (
decaf_448_precomputed_s *pre
) NONNULL1 API_VIS;

/* TODO: functions to invert point_from_hash?? */

#undef API_VIS
#undef WARN_UNUSED
#undef NOINLINE
#undef NONNULL1
#undef NONNULL2
#undef NONNULL3
#undef NONNULL4
#undef NONNULL5

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* __DECAF_448_H__ */

+ 302
- 0
include/secure_buffer.hxx View File

@@ -0,0 +1,302 @@
/**
* @file secure_buffer.hxx
* @author Mike Hamburg
*
* @copyright
* Copyright (c) 2015 Cryptography Research, Inc. \n
* Released under the MIT License. See LICENSE.txt for license information.
*
* @brief C++ self-zeroizing buffer.
*/
#ifndef __DECAF_SECURE_BUFFER_HXX__
#define __DECAF_SECURE_BUFFER_HXX__ 1

#include <string>
#include <sys/types.h>

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

namespace decaf {

/**@cond internal*/
/** Forward-declare sponge RNG object */
class Buffer;
class TmpBuffer;
class SecureBuffer;
/**@endcond*/
/** @brief An exception for when crypto (ie point decode) has failed. */
class CryptoException : public std::exception {
public:
/** @return "CryptoException" */
virtual const char * what() const NOEXCEPT { return "CryptoException"; }
};

/** @brief An exception for when crypto (ie point decode) has failed. */
class LengthException : public std::exception {
public:
/** @return "CryptoException" */
virtual const char * what() const NOEXCEPT { return "LengthException"; }
};

/** @brief Passed to constructors to avoid (conservative) initialization */
struct NOINIT {};

/** @brief Prototype of a random number generator.
* FUTURE: Are the noexcept methods really noexcept? What about self-reseeding RNGs?
*/
class Rng {
protected:
/** Empty initializer */
Rng() {}
/** Not copyable */
Rng(const Rng &) DELETE;
/** Not copyable */
Rng &operator=(const Rng &) DELETE;
public:
/** @brief Read into a Buffer */
virtual inline void read(Buffer &buffer) NOEXCEPT = 0;
/** @brief Read into a value-passed (eg temporary) TmpBuffer. */
inline void read(TmpBuffer buffer) NOEXCEPT;

/** @brief Read into a SecureBuffer. */
inline SecureBuffer read(size_t length) throw(std::bad_alloc);
};

/**
* Securely zeorize contents of memory.
*/
static inline void really_bzero(void *data, size_t size) { decaf_bzero(data,size); }

/** A reference to a block of data, which (when accessed through this base class) is const. */
class Block {
protected:
unsigned char *data_;
size_t size_;

public:
/** Empty init */
inline Block() NOEXCEPT : data_(NULL), size_(0) {}
/** Init from C string */
inline Block(const char *data) NOEXCEPT : data_((unsigned char *)data), size_(strlen(data)) {}

/** Unowned init */
inline Block(const unsigned char *data, size_t size) NOEXCEPT : data_((unsigned char *)data), size_(size) {}
/** Block from std::string */
inline Block(const std::string &s) : data_(
#if __cplusplus >= 201103L
((unsigned char *)&(s)[0])
#else
((unsigned char *)(s.data()))
#endif
), size_(s.size()) {}

/** Get const data */
inline const unsigned char *data() const NOEXCEPT { return data_; }

/** Get the size */
inline size_t size() const NOEXCEPT { return size_; }

/** Autocast to const unsigned char * */
inline operator const unsigned char*() const NOEXCEPT { return data_; }

/** Convert to C++ string */
inline std::string get_string() const {
return std::string((const char *)data_,size_);
}

/** Slice the buffer*/
inline Block slice(size_t off, size_t length) const throw(LengthException) {
if (off > size() || length > size() - off)
throw LengthException();
return Block(data()+off, length);
}
/** @cond internal */
inline decaf_bool_t operator>=(const Block &b) const NOEXCEPT DELETE;
inline decaf_bool_t operator<=(const Block &b) const NOEXCEPT DELETE;
inline decaf_bool_t operator> (const Block &b) const NOEXCEPT DELETE;
inline decaf_bool_t operator< (const Block &b) const NOEXCEPT DELETE;
/** @endcond */
/* Content-wise comparison; constant-time if they are the same length. */
inline decaf_bool_t operator!=(const Block &b) const NOEXCEPT {
if (b.size() != size()) return true;
return ~decaf_memeq(b,*this,size());
}
/* Content-wise comparison; constant-time if they are the same length. */
inline decaf_bool_t operator==(const Block &b) const NOEXCEPT {
return ~(*this == b);
}

/** Virtual destructor for SecureBlock. TODO: probably means vtable? Make bool? */
inline virtual ~Block() {};
};

/** A reference to a writable block of data */
class Buffer : public Block {
public:
/** Null init */
inline Buffer() NOEXCEPT : Block() {}

/** Unowned init */
inline Buffer(unsigned char *data, size_t size) NOEXCEPT : Block(data,size) {}

/** Get unconst data */
inline unsigned char *data() NOEXCEPT { return data_; }

/** Get const data */
inline const unsigned char *data() const NOEXCEPT { return data_; }

/** Autocast to const unsigned char * */
inline operator const unsigned char*() const NOEXCEPT { return data_; }

/** Autocast to unsigned char */
inline operator unsigned char*() NOEXCEPT { return data_; }

/** Slice the buffer*/
inline TmpBuffer slice(size_t off, size_t length) throw(LengthException);
/** Securely set the buffer to 0. */
inline void zeorize() NOEXCEPT { really_bzero(data(),size()); }
};

/** A temporary reference to a writeable buffer, for converting C to C++. */
class TmpBuffer : public Buffer {
public:
/** Unowned init */
inline TmpBuffer(unsigned char *data, size_t size) NOEXCEPT : Buffer(data,size) {}
};

/** A fixed-size stack-allocated buffer (for NOEXCEPT semantics) */
template<size_t Size> class StackBuffer : public Buffer {
private:
uint8_t storage[Size];
public:
/** New buffer initialized to zero. */
inline StackBuffer() NOEXCEPT : Buffer(storage, Size) { memset(storage,0,Size); }

/** New uninitialized buffer. */
inline StackBuffer(const NOINIT &) NOEXCEPT : Buffer(storage, Size) { }
/** New random buffer */
inline StackBuffer(Rng &r) NOEXCEPT : Buffer(storage, Size) { r.read(*this); }
/** Destroy the buffer */
~StackBuffer() NOEXCEPT { zeorize(); }
};

/** @cond internal */
inline void Rng::read(TmpBuffer buffer) NOEXCEPT { read((Buffer &)buffer); }
/** @endcond */

/** A self-erasing block of data */
class SecureBuffer : public Buffer {
public:
/** Null secure block */
inline SecureBuffer() NOEXCEPT : Buffer() {}

/** Construct empty from size */
inline SecureBuffer(size_t size) {
data_ = new unsigned char[size_ = size];
memset(data_,0,size);
}

/** Construct from data */
inline SecureBuffer(const unsigned char *data, size_t size) {
data_ = new unsigned char[size_ = size];
memcpy(data_, data, size);
}
/** Construct from random */
inline SecureBuffer(Rng &r, size_t size) NOEXCEPT {
data_ = new unsigned char[size_ = size];
r.read(*this);
}

/** Copy constructor */
inline SecureBuffer(const Block &copy) : Buffer() { *this = copy; }

/** Copy-assign constructor */
inline SecureBuffer& operator=(const Block &copy) throw(std::bad_alloc) {
if (&copy == this) return *this;
clear();
data_ = new unsigned char[size_ = copy.size()];
memcpy(data_,copy.data(),size_);
return *this;
}

/** Copy-assign constructor */
inline SecureBuffer& operator=(const SecureBuffer &copy) throw(std::bad_alloc) {
if (&copy == this) return *this;
clear();
data_ = new unsigned char[size_ = copy.size()];
memcpy(data_,copy.data(),size_);
return *this;
}

/** Destructor zeorizes data */
~SecureBuffer() NOEXCEPT { clear(); }

/** Clear data */
inline void clear() NOEXCEPT {
if (data_ == NULL) return;
zeorize();
delete[] data_;
data_ = NULL;
size_ = 0;
}

#if __cplusplus >= 201103L
/** Move constructor */
inline SecureBuffer(SecureBuffer &&move) { *this = move; }

/** Move non-constructor */
inline SecureBuffer(Block &&move) { *this = (Block &)move; }

/** Move-assign constructor. TODO: check that this actually gets used.*/
inline SecureBuffer& operator=(SecureBuffer &&move) {
clear();
data_ = move.data_; move.data_ = NULL;
size_ = move.size_; move.size_ = 0;
return *this;
}

/** C++11-only explicit cast */
inline explicit operator std::string() const { return get_string(); }
#endif
};

/** @cond internal */
TmpBuffer Buffer::slice(size_t off, size_t length) throw(LengthException) {
if (off > size() || length > size() - off) throw LengthException();
return TmpBuffer(data()+off, length);
}

inline SecureBuffer Rng::read(size_t length) throw(std::bad_alloc) {
SecureBuffer out(length); read(out); return out;
}
/** @endcond */

} /* namespace decaf */


#undef NOEXCEPT
#undef DELETE

#endif /* __DECAF_SECURE_BUFFER_HXX__ */

+ 8
- 44
include/shake.hxx View File

@@ -18,15 +18,9 @@

/** @cond internal */
#if __cplusplus >= 201103L
#define DELETE = delete
#define NOEXCEPT noexcept
#define EXPLICIT_CON explicit
#define GET_DATA(str) ((const unsigned char *)&(str)[0])
#else
#define DELETE
#define NOEXCEPT throw()
#define EXPLICIT_CON
#define GET_DATA(str) ((const unsigned char *)((str).data()))
#endif
/** @endcond */

@@ -143,9 +137,9 @@ public:
/** @return "ProtocolException" */
virtual const char * what() const NOEXCEPT { return "ProtocolException"; }
};
/** Sponge-based random-number generator */
class SpongeRng : private KeccakSponge {
class SpongeRng : public Rng, private KeccakSponge {
public:
class RngException : public std::exception {
private:
@@ -172,46 +166,19 @@ public:
}
}
/** Read data to a buffer. */
inline void read(Buffer &buffer) NOEXCEPT { spongerng_next(sp,buffer.data(),buffer.size()); }
using Rng::read;
/** Read data to a buffer. */
inline void read(TmpBuffer buffer) NOEXCEPT { read((Buffer &)buffer); }
/** Read data to a C++ string
* @warning TODO Future versions of this function may throw RngException if a
* nondeterministic RNG fails a reseed.
*/
inline SecureBuffer read(size_t length) throw(std::bad_alloc) {
SecureBuffer out(length); read(out); return out;
}
virtual inline void read(Buffer &buffer) NOEXCEPT
#if __cplusplus >= 201103L
final
#endif
{ spongerng_next(sp,buffer.data(),buffer.size()); }
private:
SpongeRng(const SpongeRng &) DELETE;
SpongeRng &operator=(const SpongeRng &) DELETE;
};

/**@cond internal*/
inline Ed255::Scalar::Scalar(SpongeRng &rng) NOEXCEPT {
*this = rng.read(SER_BYTES);
}

inline Ed255::Point::Point(SpongeRng &rng, bool uniform) NOEXCEPT {
SecureBuffer buffer((uniform ? 2 : 1) * HASH_BYTES);
rng.read(buffer);
set_to_hash(buffer);
}


inline SecureBuffer Ed255::Point::steg_encode(SpongeRng &rng) const NOEXCEPT {
SecureBuffer out(STEG_BYTES);
bool done;
do {
rng.read(out.slice(HASH_BYTES-1,STEG_BYTES-HASH_BYTES+1));
done = invert_elligator(out, out[HASH_BYTES-1]);
} while (!done);
return out;
}
/**@endcond*/

class Strobe : private KeccakSponge {
@@ -374,8 +341,5 @@ public:
} /* namespace decaf */

#undef NOEXCEPT
#undef EXPLICIT_CON
#undef GET_DATA
#undef DELETE

#endif /* __SHAKE_HXX__ */

+ 22
- 11
src/decaf_fast.c View File

@@ -29,6 +29,8 @@
#define point_t decaf_255_point_t
#define precomputed_s decaf_255_precomputed_s
#define SER_BYTES DECAF_255_SER_BYTES
#define gf_s gf_255_s
#define gf gf_255_t

#if WBITS == 64
typedef __int128_t decaf_sdword_t;
@@ -40,23 +42,14 @@ typedef int64_t decaf_sdword_t;
#error "Only supporting 32- and 64-bit platforms right now"
#endif

//static const int QUADRATIC_NONRESIDUE = -1;

#define sv static void
#define snv static void __attribute__((noinline))
#define siv static inline void __attribute__((always_inline))
static const gf ZERO = {{{0}}}, ONE = {{{1}}};//, TWO = {{{2}}};
static const gf ZERO = {{{0}}}, ONE = {{{1}}};

static const int EDWARDS_D = -121665;
// PinkBikeShed: -89747;

static const scalar_t sc_p = {{{
/* PinkBikeShed:
SC_LIMB(0xb6b98fd8849faf35),
SC_LIMB(0x16241e6093b2ce59),
SC_LIMB(0),
SC_LIMB(0x2000000000000000)
*/
SC_LIMB(0x5812631a5cf5d3ed),
SC_LIMB(0x14def9dea2f79cd6),
SC_LIMB(0),
@@ -119,7 +112,7 @@ siv gf_isqrt(gf y, const gf x) {
field_isr((field_t *)y, (const field_t *)x);
}

/** Inverse. TODO: adapt to 5-mod-8 fields? */
/** Inverse. */
sv gf_invert(gf y, const gf x) {
gf t1, t2;
gf_sqr(t1, x); // o^2
@@ -1271,6 +1264,24 @@ void API_NS(point_debugging_torque) (
#endif
}

void API_NS(point_debugging_pscale) (
point_t q,
const point_t p,
const uint8_t factor[SER_BYTES]
) {
gf gfac,tmp;
ignore_result(gf_deser(gfac,factor));
cond_sel(gfac,gfac,ONE,gf_eq(gfac,ZERO));
gf_mul(tmp,p->x,gfac);
gf_cpy(q->x,tmp);
gf_mul(tmp,p->y,gfac);
gf_cpy(q->y,tmp);
gf_mul(tmp,p->z,gfac);
gf_cpy(q->z,tmp);
gf_mul(tmp,p->t,gfac);
gf_cpy(q->t,tmp);
}

static void gf_batch_invert (
gf *__restrict__ out,
/* const */ gf *in,


+ 27
- 6
test/test_decaf.cxx View File

@@ -167,6 +167,8 @@ static void test_elligator() {
const int NHINTS = 1<<4;
decaf::SecureBuffer *alts[NHINTS];
bool successes[NHINTS];
decaf::SecureBuffer *alts2[NHINTS];
bool successes2[NHINTS];

for (int i=0; i<NTESTS/10 && (test.passing_now || i < 100); i++) {
size_t len = (i % (2*Point::HASH_BYTES + 3)); // FIXME: 0
@@ -174,17 +176,36 @@ static void test_elligator() {
if (i!=Point::HASH_BYTES) rng.read(b1); /* special test case */
if (i==1) b1[0] = 1; /* special case test */
if (len >= Point::HASH_BYTES) b1[Point::HASH_BYTES-1] &= 0x7F; // FIXME MAGIC
Point s = Point::from_hash(b1);
for (int j=0; j<(i&3); j++) s.debugging_torque_in_place();
Point s = Point::from_hash(b1), ss=s;
for (int j=0; j<(i&3); j++) ss = ss.debugging_torque();
ss = ss.debugging_pscale(rng);
bool good = false;
for (int j=0; j<NHINTS; j++) {
alts[j] = new decaf::SecureBuffer(len);
alts2[j] = new decaf::SecureBuffer(len);

if (len > Point::HASH_BYTES)
memcpy(&(*alts[j])[Point::HASH_BYTES], &b1[Point::HASH_BYTES], len-Point::HASH_BYTES);
successes[j] = s.invert_elligator(*alts[j],j);
if (len > Point::HASH_BYTES)
memcpy(&(*alts2[j])[Point::HASH_BYTES], &b1[Point::HASH_BYTES], len-Point::HASH_BYTES);
successes[j] = s.invert_elligator(*alts[j], j);
successes2[j] = ss.invert_elligator(*alts2[j],j);
if (successes[j] != successes2[j]
|| (successes[j] && successes2[j] && *alts[j] != *alts2[j])
) {
test.fail();
printf(" Unscalable Elligator inversion: i=%d, hint=%d, s=%d,%d\n",i,j,
-int(successes[j]),-int(successes2[j]));
hexprint("x",b1);
hexprint("X",*alts[j]);
hexprint("X",*alts2[j]);
}
if (successes[j]) {
good = good || (b1 == *alts[j]);
@@ -228,6 +249,8 @@ static void test_elligator() {
for (int j=0; j<NHINTS; j++) {
delete alts[j];
alts[j] = NULL;
delete alts2[j];
alts2[j] = NULL;
}
Point t(rng);
@@ -260,9 +283,7 @@ static void test_ec() {
Point r = Point::from_hash(buffer);
point_check(test,p,q,r,0,0,p,Point((decaf::SecureBuffer)p),"round-trip");
Point pp = p;
pp = p + q - q;
pp.debugging_torque_in_place();
Point pp = p.debugging_torque().debugging_pscale(rng);
if (decaf::SecureBuffer(pp) != decaf::SecureBuffer(p)) {
test.fail();
printf("Fail torque seq test\n");


Loading…
Cancel
Save