From 2162dbe78da6ae8ad5dd5a192d41573932fd9876 Mon Sep 17 00:00:00 2001 From: Mike Hamburg Date: Sat, 18 Jul 2015 14:10:21 -0700 Subject: [PATCH] add crypto.hxx that doesnt work yet --- src/public_include/decaf/crypto.hxx | 178 ++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 src/public_include/decaf/crypto.hxx diff --git a/src/public_include/decaf/crypto.hxx b/src/public_include/decaf/crypto.hxx new file mode 100644 index 0000000..b26cab6 --- /dev/null +++ b/src/public_include/decaf/crypto.hxx @@ -0,0 +1,178 @@ +/** + * @file decaf/crypto.hxx + * @author Mike Hamburg + * + * @copyright + * Copyright (c) 2015 Cryptography Research, Inc. \n + * Released under the MIT License. See LICENSE.txt for license information. + * + * @brief Example cryptography using Decaf + */ +#ifndef __DECAF_CRYPTO_HXX__ +#define __DECAF_CRYPTO_HXX__ 1 + +#include +#include + +/** @cond internal */ +#if __cplusplus >= 201103L +#define NOEXCEPT noexcept +#else +#define NOEXCEPT throw() +#endif +/** @endcond */ + +/* TODO: decide on copy vs reference */ + +namespace decaf { + +template class PrivateKey; + +/** @brief A public key using a particular EC group */ +template class PublicKey { +private: + /** @cond internal */ + friend class PrivateKey; + //const typename Group::Point p; + const FixedArrayBuffer ser; + static const size_t CHALLENGE_BYTES = Group::Scalar::SER_BYTES; + /** @endcond */ + +public: + /** SHAKE instance size for sigs etc */ + static const size_t SHAKE_BITS = 256; + + /** Size of a signature */ + static const size_t SIG_BYTES = Group::Point::SER_BYTES + Group::Scalar::SER_BYTES; + + /** @brief Return a pointer to the serialized version of the point. */ + inline operator FixedBlock() const NOEXCEPT { + return ser; + } + + /** @brief Set the public key to a point */ + inline explicit PublicKey(const typename Group::Point &p) NOEXCEPT : ser(SecureBuffer(p)) {} + + /** @brief Get the private key for a given public key */ + inline explicit PublicKey(const PrivateKey &priv) NOEXCEPT; + + /** @brief Read a private key from a string*/ + inline explicit PublicKey(const FixedBlock b) NOEXCEPT : ser(b) {} + + /** @brief Return the corresponding EC point */ + inline typename Group::Point point() const throw(CryptoException) { + return typename Group::Point(ser); + } + + /** @brief Verify a sig. TODO: nothrow version? */ + inline void verify_shake(const SHAKE &ctx_, const FixedBlock &sig) throw(CryptoException) { + SHAKE ctx(ctx_); + ctx << ser << sig.slice(0,Group::Point::SER_BYTES); + FixedBuffer challenge(ctx.output(CHALLENGE_BYTES)); + challenge.debug_print("ch ver "); + + const typename Group::Point combo = point().non_secret_combo_with_base( + challenge, + sig.slice(Group::Point::SER_BYTES, Group::Scalar::SER_BYTES) + ); + if (combo != typename Group::Point(sig.slice(0,Group::Point::SER_BYTES))) + throw CryptoException(); + } + + + + /** @brief Sign from a message. */ + inline void verify(const Block &message, const FixedBlock &sig) throw(CryptoException) { + SHAKE ctx; + ctx << message; + verify_shake(ctx,sig); + } +}; + +/** @brief A private key using a particular EC group */ +template class PrivateKey { +public: + /** Size of associated symmetric key */ + static const size_t SYM_BYTES = 32; + + /** SHAKE instance size for sigs etc */ + static const size_t SHAKE_BITS = PublicKey::SHAKE_BITS; + +private: + /** @cond internal */ + static const size_t SCALAR_HASH_BYTES = Group::Scalar::SER_BYTES + 8; + friend class PublicKey; + const FixedArrayBuffer sym; + const typename Group::Scalar scalar; + const PublicKey pub_; + /** @endcond */ + +public: + /** @brief Construct at random */ + inline PrivateKey(Rng &r) : + sym(r), + scalar(SHAKE::hash(sym, SCALAR_HASH_BYTES)), + pub_(SecureBuffer(Group::Precomputed::base() * scalar)) {} + + /** @brief Construct from buffer */ + inline PrivateKey(const FixedBlock &sym_) : + sym(sym_), + scalar(SHAKE::hash(sym, SCALAR_HASH_BYTES)), + pub_(SecureBuffer(Group::Precomputed::Base * scalar)) {} + + /** @brief Compressed representation */ + inline const FixedBlock &ser_compressed() const NOEXCEPT { + return sym; + } + + /** @brief Uncompressed representation */ + inline SecureBuffer ser_uncompressed() const throw(std::bad_alloc) { + 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); + return b; + } + + /** @brief Sign from a SHAKE context. TODO: double check random oracle eval of this; destructive version? */ + inline SecureBuffer sign_shake(const SHAKE &ctx_) NOEXCEPT { + SHAKE ctx(ctx_); + ctx << sym << "decaf_255_sign_shake"; + typename Group::Scalar nonce(ctx.output(SCALAR_HASH_BYTES)); + SecureBuffer g_nonce(Group::Precomputed::base() * nonce); /* FIXME: make output fixed size, avoid std::bad_alloc */ + + ctx = ctx_; + ctx << pub_.ser << g_nonce; + FixedBuffer::CHALLENGE_BYTES> challenge(ctx.output(PublicKey::CHALLENGE_BYTES)); + challenge.debug_print("ch sign"); + SecureBuffer response(nonce - scalar * challenge); + + SecureBuffer ret(PublicKey::SIG_BYTES); + ret.slice(0,Group::Point::SER_BYTES).assign(g_nonce); + ret.slice(Group::Point::SER_BYTES, Group::Scalar::SER_BYTES).assign(response); + return ret; + } + + /** @brief Sign from a message. */ + inline SecureBuffer sign(const Block &message) { + SHAKE ctx; + ctx << message; + return sign_shake(ctx); + } + + /** @brief Get the corresponding public key */ + inline const PublicKey &pub() const { return pub_; } +}; + +/** @cond internal */ +template +inline PublicKey::PublicKey( + const PrivateKey &priv +) NOEXCEPT : ser(priv.pub_.ser){} +/** @endcond */ + +#undef NOEXCEPT +} /* namespace decaf */ + +#endif /* __DECAF_CRYPTO_HXX__ */ +