Browse Source

switch SecureBuffer to vector

master
Michael Hamburg 9 years ago
parent
commit
4dd77e0149
7 changed files with 203 additions and 245 deletions
  1. +10
    -12
      src/public_include/decaf/crypto.hxx
  2. +23
    -13
      src/public_include/decaf/decaf_255.hxx
  3. +23
    -18
      src/public_include/decaf/decaf_448.hxx
  4. +114
    -137
      src/public_include/decaf/secure_buffer.hxx
  5. +19
    -51
      src/public_include/decaf/shake.hxx
  6. +8
    -8
      test/bench_decaf.cxx
  7. +6
    -6
      test/test_decaf.cxx

+ 10
- 12
src/public_include/decaf/crypto.hxx View File

@@ -57,7 +57,7 @@ public:
inline explicit PublicKey(const PrivateKey<Group> &priv) NOEXCEPT; inline explicit PublicKey(const PrivateKey<Group> &priv) NOEXCEPT;
/** @brief Read a private key from a string*/ /** @brief Read a private key from a string*/
inline explicit PublicKey(const FixedBlock<Group::Point::SER_BYTES> b) NOEXCEPT : ser(b) {}
inline explicit PublicKey(const FixedBlock<Group::Point::SER_BYTES> &b) NOEXCEPT : ser(b) {}
/** @brief Return the corresponding EC point */ /** @brief Return the corresponding EC point */
inline typename Group::Point point() const throw(CryptoException) { inline typename Group::Point point() const throw(CryptoException) {
@@ -68,11 +68,10 @@ public:
inline void verify_shake(const SHAKE<SHAKE_BITS> &ctx_, const FixedBlock<SIG_BYTES> &sig) throw(CryptoException) { inline void verify_shake(const SHAKE<SHAKE_BITS> &ctx_, const FixedBlock<SIG_BYTES> &sig) throw(CryptoException) {
SHAKE<SHAKE_BITS> ctx(ctx_); SHAKE<SHAKE_BITS> ctx(ctx_);
ctx << ser << sig.slice(0,Group::Point::SER_BYTES); ctx << ser << sig.slice(0,Group::Point::SER_BYTES);
FixedBuffer<CHALLENGE_BYTES> challenge(ctx.output(CHALLENGE_BYTES));
challenge.debug_print("ch ver ");
SecureBuffer challenge(ctx.output(CHALLENGE_BYTES));
const typename Group::Point combo = point().non_secret_combo_with_base( const typename Group::Point combo = point().non_secret_combo_with_base(
challenge,
typename Group::Scalar(challenge),
sig.slice(Group::Point::SER_BYTES, Group::Scalar::SER_BYTES) sig.slice(Group::Point::SER_BYTES, Group::Scalar::SER_BYTES)
); );
if (combo != typename Group::Point(sig.slice(0,Group::Point::SER_BYTES))) if (combo != typename Group::Point(sig.slice(0,Group::Point::SER_BYTES)))
@@ -128,9 +127,9 @@ public:
/** @brief Uncompressed representation */ /** @brief Uncompressed representation */
inline SecureBuffer ser_uncompressed() const throw(std::bad_alloc) { inline SecureBuffer ser_uncompressed() const throw(std::bad_alloc) {
SecureBuffer b(SYM_BYTES + Group::Scalar::SER_BYTES + Group::Point::SER_BYTES); SecureBuffer b(SYM_BYTES + Group::Scalar::SER_BYTES + Group::Point::SER_BYTES);
b.slice(0,SYM_BYTES).assign(sym);
b.slice(SYM_BYTES,Group::Scalar::SER_BYTES).assign(scalar);
b.slice(SYM_BYTES+Group::Scalar::SER_BYTES,Group::Point::SER_BYTES).assign(pub_.ser);
Buffer(b).slice(0,SYM_BYTES).assign(sym);
Buffer(b).slice(SYM_BYTES,Group::Scalar::SER_BYTES).assign(scalar);
Buffer(b).slice(SYM_BYTES+Group::Scalar::SER_BYTES,Group::Point::SER_BYTES).assign(pub_.ser);
return b; return b;
} }
@@ -143,13 +142,12 @@ public:
ctx = ctx_; ctx = ctx_;
ctx << pub_.ser << g_nonce; ctx << pub_.ser << g_nonce;
FixedBuffer<PublicKey<Group>::CHALLENGE_BYTES> challenge(ctx.output(PublicKey<Group>::CHALLENGE_BYTES));
challenge.debug_print("ch sign");
SecureBuffer response(nonce - scalar * challenge);
SecureBuffer challenge(ctx.output(PublicKey<Group>::CHALLENGE_BYTES));
SecureBuffer response((nonce - scalar * typename Group::Scalar(challenge)).encode());
SecureBuffer ret(PublicKey<Group>::SIG_BYTES); SecureBuffer ret(PublicKey<Group>::SIG_BYTES);
ret.slice(0,Group::Point::SER_BYTES).assign(g_nonce);
ret.slice(Group::Point::SER_BYTES, Group::Scalar::SER_BYTES).assign(response);
Buffer(ret).slice(0,Group::Point::SER_BYTES).assign(g_nonce);
Buffer(ret).slice(Group::Point::SER_BYTES, Group::Scalar::SER_BYTES).assign(response);
return ret; return ret;
} }


+ 23
- 13
src/public_include/decaf/decaf_255.hxx View File

@@ -130,7 +130,7 @@ public:
static inline decaf_bool_t __attribute__((warn_unused_result)) decode ( static inline decaf_bool_t __attribute__((warn_unused_result)) decode (
Scalar &sc, const FixedBlock<SER_BYTES> buffer Scalar &sc, const FixedBlock<SER_BYTES> buffer
) NOEXCEPT { ) NOEXCEPT {
return decaf_255_scalar_decode(sc.s,buffer);
return decaf_255_scalar_decode(sc.s,buffer.data());
} }
/** @brief Encode to fixed-length string */ /** @brief Encode to fixed-length string */
@@ -140,7 +140,12 @@ public:
/** @brief Encode to fixed-length buffer */ /** @brief Encode to fixed-length buffer */
inline void encode(FixedBuffer<SER_BYTES> buffer) const NOEXCEPT{ inline void encode(FixedBuffer<SER_BYTES> buffer) const NOEXCEPT{
decaf_255_scalar_encode(buffer, s);
decaf_255_scalar_encode(buffer.data(), s);
}

/** @brief Encode to fixed-length buffer */
inline SecureBuffer encode() const throw(std::bad_alloc) {
SecureBuffer buffer(SER_BYTES); encode(buffer); return buffer;
} }
/** Add. */ /** Add. */
@@ -293,15 +298,15 @@ public:
if (s.size() < HASH_BYTES) { if (s.size() < HASH_BYTES) {
SecureBuffer b(HASH_BYTES); SecureBuffer b(HASH_BYTES);
memcpy(b.data(), s.data(), s.size()); memcpy(b.data(), s.data(), s.size());
decaf_255_point_from_hash_nonuniform(p,b);
decaf_255_point_from_hash_nonuniform(p,b.data());
} else if (s.size() == HASH_BYTES) { } else if (s.size() == HASH_BYTES) {
decaf_255_point_from_hash_nonuniform(p,s);
decaf_255_point_from_hash_nonuniform(p,s.data());
} else if (s.size() < 2*HASH_BYTES) { } else if (s.size() < 2*HASH_BYTES) {
SecureBuffer b(2*HASH_BYTES); SecureBuffer b(2*HASH_BYTES);
memcpy(b.data(), s.data(), s.size()); memcpy(b.data(), s.data(), s.size());
decaf_255_point_from_hash_uniform(p,b);
decaf_255_point_from_hash_uniform(p,b.data());
} else { } else {
decaf_255_point_from_hash_uniform(p,s);
decaf_255_point_from_hash_uniform(p,s.data());
} }
} }
@@ -316,7 +321,12 @@ public:
* @brief Encode to a C buffer. The identity encodes to all zeros. * @brief Encode to a C buffer. The identity encodes to all zeros.
*/ */
inline void encode(FixedBuffer<SER_BYTES> buffer) const NOEXCEPT { inline void encode(FixedBuffer<SER_BYTES> buffer) const NOEXCEPT {
decaf_255_point_encode(buffer, p);
decaf_255_point_encode(buffer.data(), p);
}

/** @brief Encode to fixed-length buffer */
inline SecureBuffer encode() const throw(std::bad_alloc) {
SecureBuffer buffer(SER_BYTES); encode(buffer); return buffer;
} }
/** @brief Point add. */ /** @brief Point add. */
@@ -394,7 +404,7 @@ public:
/** @brief Return a point equal to *this, whose internal data has a modified representation. */ /** @brief Return a point equal to *this, whose internal data has a modified representation. */
inline Point debugging_pscale(const FixedBlock<SER_BYTES> factor) const NOEXCEPT { inline Point debugging_pscale(const FixedBlock<SER_BYTES> factor) const NOEXCEPT {
Point q; decaf_255_point_debugging_pscale(q.p,p,factor); return q;
Point q; decaf_255_point_debugging_pscale(q.p,p,factor.data()); return q;
} }
/** @brief Return a point equal to *this, whose internal data has a randomized representation. */ /** @brief Return a point equal to *this, whose internal data has a randomized representation. */
@@ -407,11 +417,11 @@ public:
* or leave buf unmodified and return false. * or leave buf unmodified and return false.
*/ */
inline bool invert_elligator ( inline bool invert_elligator (
Buffer &buf, uint16_t hint
Buffer buf, uint16_t hint
) const NOEXCEPT { ) const NOEXCEPT {
unsigned char buf2[2*HASH_BYTES]; unsigned char buf2[2*HASH_BYTES];
memset(buf2,0,sizeof(buf2)); memset(buf2,0,sizeof(buf2));
memcpy(buf2,buf,(buf.size() > 2*HASH_BYTES) ? 2*HASH_BYTES : buf.size());
memcpy(buf2,buf.data(),(buf.size() > 2*HASH_BYTES) ? 2*HASH_BYTES : buf.size());
decaf_bool_t ret; decaf_bool_t ret;
if (buf.size() > HASH_BYTES) { if (buf.size() > HASH_BYTES) {
ret = decaf_255_invert_elligator_uniform(buf2, p, hint); ret = decaf_255_invert_elligator_uniform(buf2, p, hint);
@@ -423,7 +433,7 @@ public:
} }
if (ret) { if (ret) {
/* TODO: make this constant time?? */ /* TODO: make this constant time?? */
memcpy(buf,buf2,(buf.size() < HASH_BYTES) ? buf.size() : HASH_BYTES);
memcpy(buf.data(),buf2,(buf.size() < HASH_BYTES) ? buf.size() : HASH_BYTES);
} }
decaf_bzero(buf2,sizeof(buf2)); decaf_bzero(buf2,sizeof(buf2));
return !!ret; return !!ret;
@@ -435,7 +445,7 @@ public:
SecureBuffer out(STEG_BYTES); SecureBuffer out(STEG_BYTES);
bool done; bool done;
do { do {
rng.read(out.slice(HASH_BYTES-1,STEG_BYTES-HASH_BYTES+1));
rng.read(Buffer(out).slice(HASH_BYTES-1,STEG_BYTES-HASH_BYTES+1));
done = invert_elligator(out, out[HASH_BYTES-1]); done = invert_elligator(out, out[HASH_BYTES-1]);
} while (!done); } while (!done);
return out; return out;
@@ -553,7 +563,7 @@ inline SecureBuffer IsoEd25519::Scalar::direct_scalarmul (
decaf_bool_t short_circuit decaf_bool_t short_circuit
) const throw(CryptoException) { ) const throw(CryptoException) {
SecureBuffer out(IsoEd25519::Point::SER_BYTES); SecureBuffer out(IsoEd25519::Point::SER_BYTES);
if (!decaf_255_direct_scalarmul(out, in.data(), s, allow_identity, short_circuit))
if (!decaf_255_direct_scalarmul(out.data(), in.data(), s, allow_identity, short_circuit))
throw CryptoException(); throw CryptoException();
return out; return out;
} }


+ 23
- 18
src/public_include/decaf/decaf_448.hxx View File

@@ -130,17 +130,17 @@ public:
static inline decaf_bool_t __attribute__((warn_unused_result)) decode ( static inline decaf_bool_t __attribute__((warn_unused_result)) decode (
Scalar &sc, const FixedBlock<SER_BYTES> buffer Scalar &sc, const FixedBlock<SER_BYTES> buffer
) NOEXCEPT { ) NOEXCEPT {
return decaf_448_scalar_decode(sc.s,buffer);
return decaf_448_scalar_decode(sc.s,buffer.data());
} }
/** @brief Encode to fixed-length string */
inline operator SecureBuffer() const NOEXCEPT {
SecureBuffer buf(SER_BYTES); decaf_448_scalar_encode(buf,s); return buf;
/** @brief Encode to fixed-length buffer */
inline void encode(FixedBuffer<SER_BYTES> buffer) const NOEXCEPT{
decaf_448_scalar_encode(buffer.data(), s);
} }
/** @brief Encode to fixed-length buffer */ /** @brief Encode to fixed-length buffer */
inline void encode(FixedBuffer<SER_BYTES> buffer) const NOEXCEPT{
decaf_448_scalar_encode(buffer, s);
inline SecureBuffer encode() const throw(std::bad_alloc) {
SecureBuffer buffer(SER_BYTES); encode(buffer); return buffer;
} }
/** Add. */ /** Add. */
@@ -192,7 +192,7 @@ public:
decaf_bool_t short_circuit=DECAF_TRUE decaf_bool_t short_circuit=DECAF_TRUE
) const throw(CryptoException) { ) const throw(CryptoException) {
SecureBuffer out(/*FIXME Point::*/SER_BYTES); SecureBuffer out(/*FIXME Point::*/SER_BYTES);
if (!decaf_448_direct_scalarmul(out, in.data(), s, allow_identity, short_circuit))
if (!decaf_448_direct_scalarmul(out.data(), in.data(), s, allow_identity, short_circuit))
throw CryptoException(); throw CryptoException();
return out; return out;
} }
@@ -296,15 +296,15 @@ public:
if (s.size() < HASH_BYTES) { if (s.size() < HASH_BYTES) {
SecureBuffer b(HASH_BYTES); SecureBuffer b(HASH_BYTES);
memcpy(b.data(), s.data(), s.size()); memcpy(b.data(), s.data(), s.size());
decaf_448_point_from_hash_nonuniform(p,b);
decaf_448_point_from_hash_nonuniform(p,b.data());
} else if (s.size() == HASH_BYTES) { } else if (s.size() == HASH_BYTES) {
decaf_448_point_from_hash_nonuniform(p,s);
decaf_448_point_from_hash_nonuniform(p,s.data());
} else if (s.size() < 2*HASH_BYTES) { } else if (s.size() < 2*HASH_BYTES) {
SecureBuffer b(2*HASH_BYTES); SecureBuffer b(2*HASH_BYTES);
memcpy(b.data(), s.data(), s.size()); memcpy(b.data(), s.data(), s.size());
decaf_448_point_from_hash_uniform(p,b);
decaf_448_point_from_hash_uniform(p,b.data());
} else { } else {
decaf_448_point_from_hash_uniform(p,s);
decaf_448_point_from_hash_uniform(p,s.data());
} }
} }
@@ -313,7 +313,7 @@ public:
*/ */
inline operator SecureBuffer() const NOEXCEPT { inline operator SecureBuffer() const NOEXCEPT {
SecureBuffer buffer(SER_BYTES); SecureBuffer buffer(SER_BYTES);
decaf_448_point_encode(buffer, p);
decaf_448_point_encode(buffer.data(), p);
return buffer; return buffer;
} }
@@ -321,7 +321,12 @@ public:
* @brief Encode to a C buffer. The identity encodes to all zeros. * @brief Encode to a C buffer. The identity encodes to all zeros.
*/ */
inline void encode(FixedBuffer<SER_BYTES> buffer) const NOEXCEPT{ inline void encode(FixedBuffer<SER_BYTES> buffer) const NOEXCEPT{
decaf_448_point_encode(buffer, p);
decaf_448_point_encode(buffer.data(), p);
}

/** @brief Encode to fixed-length buffer */
inline SecureBuffer encode() const throw(std::bad_alloc) {
SecureBuffer buffer(SER_BYTES); encode(buffer); return buffer;
} }
/** @brief Point add. */ /** @brief Point add. */
@@ -402,7 +407,7 @@ public:
/** @brief Return a point equal to *this, whose internal data has a modified representation. */ /** @brief Return a point equal to *this, whose internal data has a modified representation. */
inline Point debugging_pscale(const FixedBlock<SER_BYTES> factor) const NOEXCEPT { inline Point debugging_pscale(const FixedBlock<SER_BYTES> factor) const NOEXCEPT {
Point q; Point q;
decaf_448_point_debugging_pscale(q.p,p,factor);
decaf_448_point_debugging_pscale(q.p,p,factor.data());
return q; return q;
} }
@@ -417,11 +422,11 @@ public:
* or leave buf unmodified and return false. * or leave buf unmodified and return false.
*/ */
inline bool invert_elligator ( inline bool invert_elligator (
Buffer &buf, uint16_t hint
Buffer buf, uint16_t hint
) const NOEXCEPT { ) const NOEXCEPT {
unsigned char buf2[2*HASH_BYTES]; unsigned char buf2[2*HASH_BYTES];
memset(buf2,0,sizeof(buf2)); memset(buf2,0,sizeof(buf2));
memcpy(buf2,buf,(buf.size() > 2*HASH_BYTES) ? 2*HASH_BYTES : buf.size());
memcpy(buf2,buf.data(),(buf.size() > 2*HASH_BYTES) ? 2*HASH_BYTES : buf.size());
decaf_bool_t ret; decaf_bool_t ret;
if (buf.size() > HASH_BYTES) { if (buf.size() > HASH_BYTES) {
ret = decaf_448_invert_elligator_uniform(buf2, p, hint); ret = decaf_448_invert_elligator_uniform(buf2, p, hint);
@@ -433,7 +438,7 @@ public:
} }
if (ret) { if (ret) {
/* TODO: make this constant time?? */ /* TODO: make this constant time?? */
memcpy(buf,buf2,(buf.size() < HASH_BYTES) ? buf.size() : HASH_BYTES);
memcpy(buf.data(),buf2,(buf.size() < HASH_BYTES) ? buf.size() : HASH_BYTES);
} }
decaf_bzero(buf2,sizeof(buf2)); decaf_bzero(buf2,sizeof(buf2));
return !!ret; return !!ret;
@@ -444,7 +449,7 @@ public:
SecureBuffer out(STEG_BYTES); SecureBuffer out(STEG_BYTES);
bool done; bool done;
do { do {
rng.read(out.slice(HASH_BYTES-1,STEG_BYTES-HASH_BYTES+1));
rng.read(Buffer(out).slice(HASH_BYTES-1,STEG_BYTES-HASH_BYTES+1));
done = invert_elligator(out, out[HASH_BYTES-1]); done = invert_elligator(out, out[HASH_BYTES-1]);
} while (!done); } while (!done);
return out; return out;


+ 114
- 137
src/public_include/decaf/secure_buffer.hxx View File

@@ -14,6 +14,7 @@
#include <string> #include <string>
#include <sys/types.h> #include <sys/types.h>
#include <stdio.h> #include <stdio.h>
#include <vector>


/** @cond internal */ /** @cond internal */
#if __cplusplus >= 201103L #if __cplusplus >= 201103L
@@ -27,11 +28,67 @@


namespace decaf { namespace decaf {


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

/** @brief An allocator which zeros its memory on free */
template<typename T, size_t alignment = 0> class SanitizingAllocator {
/** @cond internal */
/* Based on http://www.codeproject.com/Articles/4795/C-Standard-Allocator-An-Introduction-and-Implement */
public:
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;

template<typename U> struct rebind { typedef SanitizingAllocator<U> other; };
inline SanitizingAllocator() NOEXCEPT {}
inline ~SanitizingAllocator() NOEXCEPT {}
inline SanitizingAllocator(const SanitizingAllocator &) NOEXCEPT {}
template<typename U, size_t a> inline SanitizingAllocator(const SanitizingAllocator<U, a> &) NOEXCEPT {}

inline T* address(T& r) const NOEXCEPT { return &r; }
inline const T* address(const T& r) const NOEXCEPT { return &r; }

inline T* allocate (
size_type cnt,
typename std::allocator<void>::const_pointer = 0
) throw(std::bad_alloc) {
void *v;
int ret = 0;
if (alignment) ret = posix_memalign(&v, alignment, cnt * sizeof(T));
else v = malloc(cnt * sizeof(T));
if (ret || v==NULL) throw(std::bad_alloc());
return reinterpret_cast<T*>(v);
}

inline void deallocate(T* p, size_t size) NOEXCEPT {
if (p==NULL) return;
really_bzero(reinterpret_cast<void*>(p), size);
free(reinterpret_cast<void*>(p));
}

inline size_t max_size() const NOEXCEPT { return std::numeric_limits<size_t>::max() / sizeof(T); }

inline void construct(T* p, const T& t) { new(p) T(t); }
inline void destroy(T* p) { p->~T(); }

inline bool operator==(SanitizingAllocator const&) const NOEXCEPT { return true; }
inline bool operator!=(SanitizingAllocator const&) const NOEXCEPT { return false; }
/** @endcond */
};

typedef std::vector<unsigned char, SanitizingAllocator<unsigned char, 0> > SecureBuffer;

/**@cond internal*/ /**@cond internal*/
/** Forward-declare sponge RNG object */
class Buffer; class Buffer;
class TmpBuffer;
class SecureBuffer;
/**@endcond*/ /**@endcond*/
/** @brief An exception for when crypto (ie point decode) has failed. */ /** @brief An exception for when crypto (ie point decode) has failed. */
@@ -67,19 +124,12 @@ protected:
public: public:
/** @brief Read into a Buffer */ /** @brief Read into a Buffer */
virtual void read(Buffer &buffer) NOEXCEPT = 0;
/** @brief Read into a value-passed (eg temporary) TmpBuffer. */
inline void read(TmpBuffer buffer) NOEXCEPT;
virtual void read(Buffer buffer) NOEXCEPT = 0;


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


/**
* Securely zeroize 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. */ /** A reference to a block of data, which (when accessed through this base class) is const. */
class Block { class Block {
@@ -105,16 +155,23 @@ public:
((unsigned char *)(s.data())) ((unsigned char *)(s.data()))
#endif #endif
), size_(s.size()) {} ), size_(s.size()) {}
/** Block from std::vector */
template<class alloc> inline Block(const std::vector<unsigned char,alloc> &s)
: data_(((unsigned char *)&(s)[0])), size_(s.size()) {}


/** Get const data */ /** Get const data */
inline const unsigned char *data() const NOEXCEPT { return data_; } inline const unsigned char *data() const NOEXCEPT { return data_; }
/** Subscript */
inline const unsigned char &operator[](size_t off) const throw(std::out_of_range) {
if (off >= size()) throw(std::out_of_range("decaf::Block"));
return data_[off];
}


/** Get the size */ /** Get the size */
inline size_t size() const NOEXCEPT { return 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 */ /** Convert to C++ string */
inline std::string get_string() const { inline std::string get_string() const {
return std::string((const char *)data_,size_); return std::string((const char *)data_,size_);
@@ -122,48 +179,48 @@ public:


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


/** Virtual destructor for SecureBlock. TODO: probably means vtable? Make bool? */ /** Virtual destructor for SecureBlock. TODO: probably means vtable? Make bool? */
inline virtual ~Block() {}; inline virtual ~Block() {};
/** Debugging print in hex */ /** Debugging print in hex */
inline void debug_print(const char *name = NULL) {
inline void debug_print_hex(const char *name = NULL) {
if (name) printf("%s = ", name); if (name) printf("%s = ", name);
for (size_t s = 0; s < size(); s++) printf("%02x", data_[s]); for (size_t s = 0; s < size(); s++) printf("%02x", data_[s]);
printf("\n"); printf("\n");
} }
private:
/** @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 */
}; };


/** A fixed-size block */ /** A fixed-size block */
template<size_t Size> class FixedBlock : public Block { template<size_t Size> class FixedBlock : public Block {
public: public:
/** Check a block's length. */ /** Check a block's length. */
inline FixedBlock(const Block &b) throw(LengthException) : Block(b,Size) {
inline FixedBlock(const Block &b) throw(LengthException) : Block(b.data(),Size) {
if (Size != b.size()) throw LengthException(); if (Size != b.size()) throw LengthException();
} }
/** Block from std::vector */
template<class alloc> inline FixedBlock(const std::vector<unsigned char,alloc> &s) : Block(s) {
if (Size != s.size()) throw LengthException();
}
/** Explicitly pass a C buffer. */ /** Explicitly pass a C buffer. */
inline explicit FixedBlock(const uint8_t data[Size]) NOEXCEPT : Block(data,Size) {} inline explicit FixedBlock(const uint8_t data[Size]) NOEXCEPT : Block(data,Size) {}
}; };
@@ -176,26 +233,29 @@ public:


/** Unowned init */ /** Unowned init */
inline Buffer(unsigned char *data, size_t size) NOEXCEPT : Block(data,size) {} inline Buffer(unsigned char *data, size_t size) NOEXCEPT : Block(data,size) {}
/** Get unconst data */
inline unsigned char *data() NOEXCEPT { return data_; }
/** Block from std::vector */
template<class alloc> inline Buffer(std::vector<unsigned char,alloc> &s) : Block(s) {}


/** Get const data */ /** Get const data */
inline const unsigned char *data() const NOEXCEPT { return 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_; }
/** Cast to unsigned char */
inline unsigned char* data() NOEXCEPT { return data_; }


/** Slice the buffer*/ /** Slice the buffer*/
inline TmpBuffer slice(size_t off, size_t length) throw(LengthException);
inline Buffer slice(size_t off, size_t length) throw(LengthException);
/** Subscript */
inline unsigned char &operator[](size_t off) throw(std::out_of_range) {
if (off >= size()) throw(std::out_of_range("decaf::Buffer"));
return data_[off];
}
/** Copy from another block */ /** Copy from another block */
inline void assign(const Block b) throw(LengthException) { inline void assign(const Block b) throw(LengthException) {
if (b.size() != size()) throw LengthException(); if (b.size() != size()) throw LengthException();
memmove(*this,b,size());
memmove(data(),b.data(),size());
} }
/** Securely set the buffer to 0. */ /** Securely set the buffer to 0. */
@@ -207,7 +267,12 @@ public:
template<size_t Size> class FixedBuffer : public Buffer { template<size_t Size> class FixedBuffer : public Buffer {
public: public:
/** Check a block's length. */ /** Check a block's length. */
inline FixedBuffer(Buffer &b) throw(LengthException) : Buffer(b,Size) {
inline FixedBuffer(Buffer b) throw(LengthException) : Buffer(b) {
if (Size != b.size()) throw LengthException();
}
/** Check a block's length. */
inline FixedBuffer(SecureBuffer &b) throw(LengthException) : Buffer(b) {
if (Size != b.size()) throw LengthException(); if (Size != b.size()) throw LengthException();
} }
@@ -220,13 +285,6 @@ public:
} }
}; };


/** 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) */ /** A fixed-size stack-allocated buffer (for NOEXCEPT semantics) */
template<size_t Size> class FixedArrayBuffer : public FixedBuffer<Size> { template<size_t Size> class FixedArrayBuffer : public FixedBuffer<Size> {
private: private:
@@ -245,18 +303,18 @@ public:
/** Copy constructor */ /** Copy constructor */
inline explicit FixedArrayBuffer(const FixedBlock<Size> &b) NOEXCEPT : FixedBuffer<Size>(storage) { inline explicit FixedArrayBuffer(const FixedBlock<Size> &b) NOEXCEPT : FixedBuffer<Size>(storage) {
memcpy(storage,b,Size);
memcpy(storage,b.data(),Size);
} }
/** Copy constructor */ /** Copy constructor */
inline explicit FixedArrayBuffer(const Block &b) throw(LengthException) : FixedBuffer<Size>(storage) { inline explicit FixedArrayBuffer(const Block &b) throw(LengthException) : FixedBuffer<Size>(storage) {
if (b.size() != Size) throw LengthException(); if (b.size() != Size) throw LengthException();
memcpy(storage,b,Size);
memcpy(storage,b.data(),Size);
} }
/** Copy constructor */ /** Copy constructor */
inline explicit FixedArrayBuffer(const FixedArrayBuffer<Size> &b) NOEXCEPT : FixedBuffer<Size>(storage) { inline explicit FixedArrayBuffer(const FixedArrayBuffer<Size> &b) NOEXCEPT : FixedBuffer<Size>(storage) {
memcpy(storage,b,Size);
memcpy(storage,b.data(),Size);
} }
/** Destroy the buffer */ /** Destroy the buffer */
@@ -264,90 +322,9 @@ public:
}; };


/** @cond internal */ /** @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) throw(std::bad_alloc) {
data_ = new unsigned char[size_ = size];
memset(data_,0,size);
}

/** Construct from data */
inline SecureBuffer(const unsigned char *data, size_t size) throw(std::bad_alloc) {
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) throw(std::bad_alloc) : 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 zeroizes data */
~SecureBuffer() NOEXCEPT { clear(); }

/** Clear data */
inline void clear() NOEXCEPT {
if (data_ == NULL) return;
zeroize();
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) {
Buffer Buffer::slice(size_t off, size_t length) throw(LengthException) {
if (off > size() || length > size() - off) throw LengthException(); if (off > size() || length > size() - off) throw LengthException();
return TmpBuffer(data()+off, length);
return Buffer(data()+off, length);
} }


inline SecureBuffer Rng::read(size_t length) throw(std::bad_alloc) { inline SecureBuffer Rng::read(size_t length) throw(std::bad_alloc) {


+ 19
- 51
src/public_include/decaf/shake.hxx View File

@@ -71,7 +71,7 @@ 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(TmpBuffer b) { sha3_output(sp,b.data(),b.size()); }
inline void output(Buffer b) { sha3_output(sp,b.data(),b.size()); }
/** /**
* @brief Output bytes from the sponge. * @brief Output bytes from the sponge.
@@ -82,7 +82,7 @@ public:
/** @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.data(),len);
return buffer; return buffer;
} }
@@ -182,7 +182,7 @@ public:
using Rng::read; using Rng::read;
/** Read data to a buffer. */ /** Read data to a buffer. */
virtual inline void read(Buffer &buffer) NOEXCEPT
virtual inline void read(Buffer buffer) NOEXCEPT
#if __cplusplus >= 201103L #if __cplusplus >= 201103L
final final
#endif #endif
@@ -211,43 +211,37 @@ public:
inline void key ( inline void key (
const Block &data, bool more = false const Block &data, bool more = false
) throw(ProtocolException) { ) throw(ProtocolException) {
if (!strobe_key(sp, data, data.size(), more)) throw ProtocolException();
if (!strobe_key(sp, data.data(), data.size(), more)) throw ProtocolException();
} }


inline void nonce(const Block &data, bool more = false inline void nonce(const Block &data, bool more = false
) throw(ProtocolException) { ) throw(ProtocolException) {
if (!strobe_nonce(sp, data, data.size(), more)) throw ProtocolException();
if (!strobe_nonce(sp, data.data(), data.size(), more)) throw ProtocolException();
} }


inline void send_plaintext(const Block &data, bool more = false inline void send_plaintext(const Block &data, bool more = false
) throw(ProtocolException) { ) throw(ProtocolException) {
if (!strobe_plaintext(sp, data, data.size(), true, more))
if (!strobe_plaintext(sp, data.data(), data.size(), true, more))
throw(ProtocolException()); throw(ProtocolException());
} }


inline void recv_plaintext(const Block &data, bool more = false inline void recv_plaintext(const Block &data, bool more = false
) throw(ProtocolException) { ) throw(ProtocolException) {
if (!strobe_plaintext(sp, data, data.size(), false, more))
if (!strobe_plaintext(sp, data.data(), data.size(), false, more))
throw(ProtocolException()); throw(ProtocolException());
} }


inline void ad(const Block &data, bool more = false inline void ad(const Block &data, bool more = false
) throw(ProtocolException) { ) throw(ProtocolException) {
if (!strobe_ad(sp, data, data.size(), more))
if (!strobe_ad(sp, data.data(), data.size(), more))
throw(ProtocolException()); throw(ProtocolException());
} }
inline void encrypt_no_auth( inline void encrypt_no_auth(
Buffer &out, const Block &data, bool more = false
Buffer out, const Block &data, bool more = false
) throw(LengthException,ProtocolException) { ) throw(LengthException,ProtocolException) {
if (out.size() != data.size()) throw LengthException(); if (out.size() != data.size()) throw LengthException();
if (!strobe_encrypt(sp, out, data, data.size(), more)) throw(ProtocolException());
}
inline void encrypt_no_auth(
TmpBuffer out, const Block &data, bool more = false
) throw(LengthException,ProtocolException) {
encrypt_no_auth((Buffer &)out, data, more);
if (!strobe_encrypt(sp, out.data(), data.data(), data.size(), more)) throw(ProtocolException());
} }
inline SecureBuffer encrypt_no_auth(const Block &data, bool more = false inline SecureBuffer encrypt_no_auth(const Block &data, bool more = false
@@ -256,16 +250,10 @@ public:
} }
inline void decrypt_no_auth( inline void decrypt_no_auth(
Buffer &out, const Block &data, bool more = false
Buffer out, const Block &data, bool more = false
) throw(LengthException,ProtocolException) { ) throw(LengthException,ProtocolException) {
if (out.size() != data.size()) throw LengthException(); if (out.size() != data.size()) throw LengthException();
if (!strobe_decrypt(sp, out, data, data.size(), more)) throw ProtocolException();
}
inline void decrypt_no_auth(
TmpBuffer out, const Block &data, bool more = false
) throw(LengthException,ProtocolException) {
decrypt_no_auth((Buffer &)out, data, more);
if (!strobe_decrypt(sp, out.data(), data.data(), data.size(), more)) throw ProtocolException();
} }
inline SecureBuffer decrypt_no_auth(const Block &data, bool more = false inline SecureBuffer decrypt_no_auth(const Block &data, bool more = false
@@ -273,13 +261,9 @@ public:
SecureBuffer out(data.size()); decrypt_no_auth(out, data, more); return out; SecureBuffer out(data.size()); decrypt_no_auth(out, data, more); return out;
} }
inline void produce_auth(Buffer &out) throw(LengthException,ProtocolException) {
inline void produce_auth(Buffer out) throw(LengthException,ProtocolException) {
if (out.size() > STROBE_MAX_AUTH_BYTES) throw LengthException(); if (out.size() > STROBE_MAX_AUTH_BYTES) throw LengthException();
if (!strobe_produce_auth(sp, out, out.size())) throw ProtocolException();
}
inline void produce_auth(TmpBuffer out) throw(LengthException,ProtocolException) {
produce_auth((Buffer &)out);
if (!strobe_produce_auth(sp, out.data(), out.size())) throw ProtocolException();
} }
inline SecureBuffer produce_auth( inline SecureBuffer produce_auth(
@@ -289,19 +273,13 @@ public:
} }
inline void encrypt( inline void encrypt(
Buffer &out, const Block &data, uint8_t auth = 8
Buffer out, const Block &data, uint8_t auth = 8
) throw(LengthException,ProtocolException) { ) throw(LengthException,ProtocolException) {
if (out.size() < data.size() || out.size() != data.size() + auth) throw LengthException(); if (out.size() < data.size() || out.size() != data.size() + auth) throw LengthException();
encrypt_no_auth(out.slice(0,data.size()), data); encrypt_no_auth(out.slice(0,data.size()), data);
produce_auth(out.slice(data.size(),auth)); produce_auth(out.slice(data.size(),auth));
} }
inline void encrypt (
TmpBuffer out, const Block &data, uint8_t auth = 8
) throw(LengthException,ProtocolException) {
encrypt((Buffer &)out, data, auth);
}
inline SecureBuffer encrypt ( inline SecureBuffer encrypt (
const Block &data, uint8_t auth = 8 const Block &data, uint8_t auth = 8
) throw(LengthException,ProtocolException,std::bad_alloc ){ ) throw(LengthException,ProtocolException,std::bad_alloc ){
@@ -309,19 +287,13 @@ public:
} }
inline void decrypt ( inline void decrypt (
Buffer &out, const Block &data, uint8_t bytes = 8
Buffer out, const Block &data, uint8_t bytes = 8
) throw(LengthException, CryptoException, ProtocolException) { ) throw(LengthException, CryptoException, ProtocolException) {
if (out.size() > data.size() || out.size() != data.size() - bytes) throw LengthException(); if (out.size() > data.size() || out.size() != data.size() - bytes) throw LengthException();
decrypt_no_auth(out, data.slice(0,out.size())); decrypt_no_auth(out, data.slice(0,out.size()));
verify_auth(data.slice(out.size(),bytes)); verify_auth(data.slice(out.size(),bytes));
} }
inline void decrypt (
TmpBuffer out, const Block &data, uint8_t bytes = 8
) throw(LengthException,CryptoException,ProtocolException) {
decrypt((Buffer &)out, data, bytes);
}
inline SecureBuffer decrypt ( inline SecureBuffer decrypt (
const Block &data, uint8_t bytes = 8 const Block &data, uint8_t bytes = 8
) throw(LengthException,CryptoException,ProtocolException,std::bad_alloc) { ) throw(LengthException,CryptoException,ProtocolException,std::bad_alloc) {
@@ -331,15 +303,11 @@ public:
inline void verify_auth(const Block &auth) throw(LengthException,CryptoException) { inline void verify_auth(const Block &auth) throw(LengthException,CryptoException) {
if (auth.size() == 0 || auth.size() > STROBE_MAX_AUTH_BYTES) throw LengthException(); if (auth.size() == 0 || auth.size() > STROBE_MAX_AUTH_BYTES) throw LengthException();
if (!strobe_verify_auth(sp, auth, auth.size())) throw CryptoException();
}
inline void prng(Buffer &out, bool more = false) NOEXCEPT {
(void)strobe_prng(sp, out, out.size(), more);
if (!strobe_verify_auth(sp, auth.data(), auth.size())) throw CryptoException();
} }
inline void prng(TmpBuffer out, bool more = false) NOEXCEPT {
prng((Buffer &)out, more);
inline void prng(Buffer out, bool more = false) NOEXCEPT {
(void)strobe_prng(sp, out.data(), out.size(), more);
} }
inline SecureBuffer prng(size_t bytes, bool more = false) { inline SecureBuffer prng(size_t bytes, bool more = false) {


+ 8
- 8
test/bench_decaf.cxx View File

@@ -361,25 +361,25 @@ int main(int argc, char **argv) {
SHA3<512> sha5; SHA3<512> sha5;
Strobe strobe(Strobe::CLIENT); Strobe strobe(Strobe::CLIENT);
unsigned char b1024[1024] = {1}; unsigned char b1024[1024] = {1};
for (Benchmark b("SHAKE128 1kiB", 30); b.iter(); ) { shake1 += TmpBuffer(b1024,1024); }
for (Benchmark b("SHAKE256 1kiB", 30); b.iter(); ) { shake2 += TmpBuffer(b1024,1024); }
for (Benchmark b("SHA3-512 1kiB", 30); b.iter(); ) { sha5 += TmpBuffer(b1024,1024); }
strobe.key(TmpBuffer(b1024,1024));
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); }
strobe.key(Buffer(b1024,1024));
strobe.respec(STROBE_128); strobe.respec(STROBE_128);
for (Benchmark b("STROBE128 1kiB", 10); b.iter(); ) { for (Benchmark b("STROBE128 1kiB", 10); b.iter(); ) {
strobe.encrypt_no_auth(TmpBuffer(b1024,1024),TmpBuffer(b1024,1024),b.i>1);
strobe.encrypt_no_auth(Buffer(b1024,1024),Buffer(b1024,1024),b.i>1);
} }
strobe.respec(STROBE_256); strobe.respec(STROBE_256);
for (Benchmark b("STROBE256 1kiB", 10); b.iter(); ) { for (Benchmark b("STROBE256 1kiB", 10); b.iter(); ) {
strobe.encrypt_no_auth(TmpBuffer(b1024,1024),TmpBuffer(b1024,1024),b.i>1);
strobe.encrypt_no_auth(Buffer(b1024,1024),Buffer(b1024,1024),b.i>1);
} }
strobe.respec(STROBE_KEYED_128); strobe.respec(STROBE_KEYED_128);
for (Benchmark b("STROBEk128 1kiB", 10); b.iter(); ) { for (Benchmark b("STROBEk128 1kiB", 10); b.iter(); ) {
strobe.encrypt_no_auth(TmpBuffer(b1024,1024),TmpBuffer(b1024,1024),b.i>1);
strobe.encrypt_no_auth(Buffer(b1024,1024),Buffer(b1024,1024),b.i>1);
} }
strobe.respec(STROBE_KEYED_256); strobe.respec(STROBE_KEYED_256);
for (Benchmark b("STROBEk256 1kiB", 10); b.iter(); ) { for (Benchmark b("STROBEk256 1kiB", 10); b.iter(); ) {
strobe.encrypt_no_auth(TmpBuffer(b1024,1024),TmpBuffer(b1024,1024),b.i>1);
strobe.encrypt_no_auth(Buffer(b1024,1024),Buffer(b1024,1024),b.i>1);
} }
/* TODO: scalarmul for verif, etc */ /* TODO: scalarmul for verif, etc */
Benches<IsoEd25519>::micro(); Benches<IsoEd25519>::micro();


+ 6
- 6
test/test_decaf.cxx View File

@@ -303,8 +303,8 @@ static void test_ec() {
point_check(test,base,q,r,x,y,x*base+y*q,q.non_secret_combo_with_base(y,x),"ds vt mul"); point_check(test,base,q,r,x,y,x*base+y*q,q.non_secret_combo_with_base(y,x),"ds vt mul");
point_check(test,p,q,r,x,0,Precomputed(p)*x,p*x,"precomp mul"); point_check(test,p,q,r,x,0,Precomputed(p)*x,p*x,"precomp mul");
point_check(test,p,q,r,0,0,r, point_check(test,p,q,r,0,0,r,
Point::from_hash(buffer.slice(0,Point::HASH_BYTES))
+ Point::from_hash(buffer.slice(Point::HASH_BYTES,Point::HASH_BYTES)),
Point::from_hash(Buffer(buffer).slice(0,Point::HASH_BYTES))
+ Point::from_hash(Buffer(buffer).slice(Point::HASH_BYTES,Point::HASH_BYTES)),
"unih = hash+add" "unih = hash+add"
); );
@@ -320,8 +320,8 @@ static void test_crypto() {
PrivateKey<Group> priv1(rng), priv2(rng); PrivateKey<Group> priv1(rng), priv2(rng);
PublicKey<Group> pub1(priv1), pub2(priv2); PublicKey<Group> pub1(priv1), pub2(priv2);
SecureBuffer message(rng, i);
FixedArrayBuffer<PublicKey<Group>::SIG_BYTES> sig(priv1.sign(message));
SecureBuffer message = rng.read(i);
SecureBuffer sig(priv1.sign(message));
pub1.verify(message, sig); pub1.verify(message, sig);
} }
} }
@@ -341,8 +341,8 @@ static void test_decaf() {
const char *message = "Hello, world!"; const char *message = "Hello, world!";


for (int i=0; i<NTESTS && test.passing_now; i++) { for (int i=0; i<NTESTS && test.passing_now; i++) {
rng.read(TmpBuffer(proto1,sizeof(proto1)));
rng.read(TmpBuffer(proto2,sizeof(proto2)));
rng.read(Buffer(proto1,sizeof(proto1)));
rng.read(Buffer(proto2,sizeof(proto2)));
decaf_255_derive_private_key(s1,proto1); decaf_255_derive_private_key(s1,proto1);
decaf_255_private_to_public(p1,s1); decaf_255_private_to_public(p1,s1);
decaf_255_derive_private_key(s2,proto2); decaf_255_derive_private_key(s2,proto2);


Loading…
Cancel
Save