Browse Source

Merge branch 'develop-evmcc' into pr-jit

cl-refactor
Paweł Bylica 10 years ago
parent
commit
e6c5299e81
  1. 14
      alethzero/MainWin.cpp
  2. 1
      alethzero/MainWin.h
  3. 1
      libdevcore/Common.h
  4. 31
      libdevcore/CommonJS.cpp
  5. 11
      libdevcore/CommonJS.h
  6. 4
      libdevcore/Exceptions.h
  7. 1
      libdevcore/FixedHash.h
  8. 48
      libdevcrypto/AES.cpp
  9. 89
      libdevcrypto/AES.h
  10. 8
      libdevcrypto/All.h
  11. 111
      libdevcrypto/Common.cpp
  12. 23
      libdevcrypto/Common.h
  13. 199
      libdevcrypto/CryptoPP.cpp
  14. 84
      libdevcrypto/CryptoPP.h
  15. 202
      libdevcrypto/EC.cpp
  16. 62
      libdevcrypto/EC.h
  17. 100
      libdevcrypto/ECDHE.cpp
  18. 109
      libdevcrypto/ECDHE.h
  19. 10
      libdevcrypto/SHA3.cpp
  20. 3
      libdevcrypto/SHA3.h
  21. 38
      libdevcrypto/SHA3MAC.h
  22. 27
      libethcore/CommonEth.cpp
  23. 36
      libethcore/CryptoHeaders.h
  24. 6
      libethereum/Executive.cpp
  25. 10
      libethereum/State.cpp
  26. 2
      libevm/VM.h
  27. 10
      libp2p/Host.cpp
  28. 1
      libqethereum/QEthereum.h
  29. 14
      libweb3jsonrpc/WebThreeStubServer.cpp
  30. 2
      libwhisper/Common.cpp
  31. 7
      libwhisper/Common.h
  32. 326
      stdserv.js
  33. 51
      test/TestHelperCrypto.h
  34. 277
      test/crypto.cpp
  35. 6
      windows/LibEthereum.vcxproj
  36. 6
      windows/LibEthereum.vcxproj.filters

14
alethzero/MainWin.cpp

@ -353,8 +353,16 @@ void Main::on_enableOptimizer_triggered()
on_data_textChanged(); on_data_textChanged();
} }
QString Main::contents(QString _s)
{
return QString::fromStdString(dev::asString(dev::contents(_s.toStdString())));
}
void Main::load(QString _s) void Main::load(QString _s)
{ {
QString contents = QString::fromStdString(dev::asString(dev::contents(_s.toStdString())));
ui->webView->page()->currentFrame()->evaluateJavaScript(contents);
/*
QFile fin(_s); QFile fin(_s);
if (!fin.open(QFile::ReadOnly)) if (!fin.open(QFile::ReadOnly))
return; return;
@ -375,7 +383,7 @@ void Main::load(QString _s)
//eval(line); //eval(line);
line.clear(); line.clear();
} }
} }*/
} }
void Main::on_loadJS_triggered() void Main::on_loadJS_triggered()
@ -679,7 +687,7 @@ void Main::on_importKeyFile_triggered()
try try
{ {
js::mValue val; js::mValue val;
json_spirit::read_string(asString(contents(s.toStdString())), val); json_spirit::read_string(asString(dev::contents(s.toStdString())), val);
auto obj = val.get_obj(); auto obj = val.get_obj();
if (obj["encseed"].type() == js::str_type) if (obj["encseed"].type() == js::str_type)
{ {
@ -948,7 +956,7 @@ void Main::refreshBlockCount()
cwatch << "refreshBlockCount()"; cwatch << "refreshBlockCount()";
auto d = ethereum()->blockChain().details(); auto d = ethereum()->blockChain().details();
auto diff = BlockInfo(ethereum()->blockChain().block()).difficulty; auto diff = BlockInfo(ethereum()->blockChain().block()).difficulty;
ui->blockCount->setText(QString("%6 #%1 @%3 T%2 N%4 D%5").arg(d.number).arg(toLog2(d.totalDifficulty)).arg(toLog2(diff)).arg(dev::eth::c_protocolVersion).arg(dev::eth::c_databaseVersion).arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet")); ui->blockCount->setText(QString("%6 #%1 @%3 T%2 PV%4 D%5").arg(d.number).arg(toLog2(d.totalDifficulty)).arg(toLog2(diff)).arg(dev::eth::c_protocolVersion).arg(dev::eth::c_databaseVersion).arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet"));
} }
static bool blockMatch(string const& _f, dev::eth::BlockDetails const& _b, h256 _h, BlockChain const& _bc) static bool blockMatch(string const& _f, dev::eth::BlockDetails const& _b, h256 _h, BlockChain const& _bc)

1
alethzero/MainWin.h

@ -85,6 +85,7 @@ public slots:
void note(QString _entry); void note(QString _entry);
void debug(QString _entry); void debug(QString _entry);
void warn(QString _entry); void warn(QString _entry);
QString contents(QString _file);
void onKeysChanged(); void onKeysChanged();

1
libdevcore/Common.h

@ -59,6 +59,7 @@ using bytesConstRef = vector_ref<byte const>;
// Numeric types. // Numeric types.
using bigint = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<>>; using bigint = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<>>;
using u128 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<128, 128, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
using u256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>; using u256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
using s256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>; using s256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>;
using u160 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<160, 160, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>; using u160 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<160, 160, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;

31
libdevcore/CommonJS.cpp

@ -38,31 +38,20 @@ bytes jsToBytes(std::string const& _s)
return bytes(); return bytes();
} }
std::string jsPadded(std::string const& _s, unsigned _l, unsigned _r) bytes padded(bytes _b, unsigned _l)
{ {
bytes b = jsToBytes(_s); while (_b.size() < _l)
while (b.size() < _l) _b.insert(_b.begin(), 0);
b.insert(b.begin(), 0); while (_b.size() < _l)
while (b.size() < _r) _b.push_back(0);
b.push_back(0); return asBytes(asString(_b).substr(_b.size() - std::max(_l, _l)));
return asString(b).substr(b.size() - std::max(_l, _r));
} }
std::string jsPadded(std::string const& _s, unsigned _l) bytes unpadded(bytes _b)
{ {
if (_s.substr(0, 2) == "0x" || _s.find_first_not_of("0123456789") == std::string::npos) auto p = asString(_b).find_last_not_of((char)0);
// Numeric: pad to right _b.resize(p == std::string::npos ? 0 : (p + 1));
return jsPadded(_s, _l, _l); return _b;
else
// Text: pad to the left
return jsPadded(_s, 0, _l);
}
std::string jsUnpadded(std::string _s)
{
auto p = _s.find_last_not_of((char)0);
_s.resize(p == std::string::npos ? 0 : (p + 1));
return _s;
} }
} }

11
libdevcore/CommonJS.h

@ -47,9 +47,8 @@ inline std::string toJS(dev::bytes const& _n)
} }
bytes jsToBytes(std::string const& _s); bytes jsToBytes(std::string const& _s);
std::string jsPadded(std::string const& _s, unsigned _l, unsigned _r); bytes padded(bytes _b, unsigned _l);
std::string jsPadded(std::string const& _s, unsigned _l); bytes unpadded(bytes _s);
std::string jsUnpadded(std::string _s);
template <unsigned N> FixedHash<N> jsToFixed(std::string const& _s) template <unsigned N> FixedHash<N> jsToFixed(std::string const& _s)
{ {
@ -61,7 +60,7 @@ template <unsigned N> FixedHash<N> jsToFixed(std::string const& _s)
return (typename FixedHash<N>::Arith)(_s); return (typename FixedHash<N>::Arith)(_s);
else else
// Binary // Binary
return FixedHash<N>(asBytes(jsPadded(_s, N))); return FixedHash<N>(); // FAIL
} }
inline std::string jsToFixed(double _s) inline std::string jsToFixed(double _s)
@ -79,7 +78,7 @@ template <unsigned N> boost::multiprecision::number<boost::multiprecision::cpp_i
return boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>(_s); return boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>(_s);
else else
// Binary // Binary
return fromBigEndian<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>>(asBytes(jsPadded(_s, N))); return 0; // FAIL
} }
inline Address jsToAddress(std::string const& _s) { return jsToFixed<sizeof(dev::Address)>(_s); } inline Address jsToAddress(std::string const& _s) { return jsToFixed<sizeof(dev::Address)>(_s); }
@ -89,7 +88,7 @@ inline u256 jsToU256(std::string const& _s) { return jsToInt<32>(_s); }
inline std::string jsToBinary(std::string const& _s) inline std::string jsToBinary(std::string const& _s)
{ {
return jsUnpadded(dev::toString(jsToBytes(_s))); return dev::toString(unpadded(jsToBytes(_s)));
} }
inline std::string jsToDecimal(std::string const& _s) inline std::string jsToDecimal(std::string const& _s)

4
libdevcore/Exceptions.h

@ -45,7 +45,7 @@ struct FileError: virtual Exception {};
typedef boost::error_info<struct tag_invalidSymbol, char> errinfo_invalidSymbol; typedef boost::error_info<struct tag_invalidSymbol, char> errinfo_invalidSymbol;
typedef boost::error_info<struct tag_address, std::string> errinfo_wrongAddress; typedef boost::error_info<struct tag_address, std::string> errinfo_wrongAddress;
typedef boost::error_info<struct tag_comment, std::string> errinfo_comment; typedef boost::error_info<struct tag_comment, std::string> errinfo_comment;
typedef boost::error_info<struct tag_required, size_t> errinfo_required; typedef boost::error_info<struct tag_required, bigint> errinfo_required;
typedef boost::error_info<struct tag_got, size_t> errinfo_got; typedef boost::error_info<struct tag_got, bigint> errinfo_got;
typedef boost::tuple<errinfo_required, errinfo_got> RequirementError; typedef boost::tuple<errinfo_required, errinfo_got> RequirementError;
} }

1
libdevcore/FixedHash.h

@ -240,6 +240,7 @@ using h520 = FixedHash<65>;
using h512 = FixedHash<64>; using h512 = FixedHash<64>;
using h256 = FixedHash<32>; using h256 = FixedHash<32>;
using h160 = FixedHash<20>; using h160 = FixedHash<20>;
using h128 = FixedHash<16>;
using h512s = std::vector<h512>; using h512s = std::vector<h512>;
using h256s = std::vector<h256>; using h256s = std::vector<h256>;
using h160s = std::vector<h160>; using h160s = std::vector<h160>;

48
libdevcrypto/SHA3MAC.cpp → libdevcrypto/AES.cpp

@ -1,40 +1,60 @@
/* /*
This file is part of cpp-ethereum. This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful, cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file SHA3MAC.cpp /** @file AES.cpp
* @author Alex Leverington <nessence@gmail.com> * @author Alex Leverington <nessence@gmail.com>
* @date 2014 * @date 2014
*
* SHA3 MAC
*/ */
#include "CryptoPP.h" #include "CryptoPP.h"
#include "SHA3MAC.h" #include "AES.h"
using namespace std;
using namespace dev; using namespace dev;
using namespace dev::crypto; using namespace dev::crypto;
using namespace dev::crypto::aes;
using namespace CryptoPP; using namespace CryptoPP;
void crypto::sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output) struct aes::Aes128Ctr
{
Aes128Ctr(h128 _k)
{
mode.SetKeyWithIV(_k.data(), sizeof(h128), Nonce::get().data());
}
CTR_Mode<AES>::Encryption mode;
};
Stream::Stream(StreamType, h128 _ckey):
m_cSecret(_ckey)
{
cryptor = new Aes128Ctr(_ckey);
}
Stream::~Stream()
{
delete cryptor;
}
void Stream::update(bytesRef)
{
}
size_t Stream::streamOut(bytes&)
{ {
CryptoPP::SHA3_256 ctx; return 0;
assert(_secret.size() > 0);
ctx.Update((byte*)_secret.data(), _secret.size());
ctx.Update((byte*)_plain.data(), _plain.size());
assert(_output.size() >= 32);
ctx.Final(_output.data());
} }

89
libdevcrypto/AES.h

@ -0,0 +1,89 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file AES.h
* @author Alex Leverington <nessence@gmail.com>
* @date 2014
*
* AES
* todo: use openssl
*/
#pragma once
#include <atomic>
#include "Common.h"
namespace dev
{
namespace crypto
{
namespace aes
{
struct Aes128Ctr;
enum StreamType { Encrypt, Decrypt };
/**
* @brief Encrypted stream
*/
class Stream
{
public:
// streamtype maybe irrelevant w/ctr
Stream(StreamType _t, h128 _ckey);
~Stream();
virtual void update(bytesRef io_bytes);
/// Move ciphertext to _bytes.
virtual size_t streamOut(bytes& o_bytes);
private:
Stream(Stream const&) = delete;
Stream& operator=(Stream const&) = delete;
h128 m_cSecret;
bytes m_text;
Aes128Ctr* cryptor;
};
/**
* @brief Encrypted stream with inband SHA3 mac at specific interval.
*/
class AuthenticatedStream: public Stream
{
public:
AuthenticatedStream(StreamType _t, h128 _ckey, h128 _mackey, unsigned _interval): Stream(_t, _ckey), m_macSecret(_mackey) { m_macInterval = _interval; }
AuthenticatedStream(StreamType _t, Secret const& _s, unsigned _interval): Stream(_t, h128(_s)), m_macSecret(FixedHash<16>((byte const*)_s.data()+16,h128::ConstructFromPointer)) { m_macInterval = _interval; }
/// Adjust mac interval. Next mac will be xored with value.
void adjustInterval(unsigned _interval) { m_macInterval = _interval; }
private:
AuthenticatedStream(AuthenticatedStream const&) = delete;
AuthenticatedStream& operator=(AuthenticatedStream const&) = delete;
std::atomic<unsigned> m_macInterval;
h128 m_macSecret;
};
}
}
}

8
libdevcrypto/All.h

@ -1,12 +1,8 @@
#pragma once #pragma once
#include "Common.h" #include "Common.h"
#include "CryptoPP.h" #include "AES.h"
#include "EC.h" #include "ECDHE.h"
#include "FileSystem.h" #include "FileSystem.h"
#include "MemoryDB.h"
#include "OverlayDB.h"
#include "SHA3.h" #include "SHA3.h"
#include "SHA3MAC.h"
#include "TrieCommon.h"
#include "TrieDB.h" #include "TrieDB.h"

111
libdevcrypto/Common.cpp

@ -23,89 +23,104 @@
#include <random> #include <random>
#include <chrono> #include <chrono>
#include <mutex> #include <mutex>
#include "EC.h"
#include "SHA3.h" #include "SHA3.h"
#include "FileSystem.h" #include "FileSystem.h"
#include "CryptoPP.h"
#include "Common.h" #include "Common.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace crypto; using namespace dev::crypto;
//#define ETH_ADDRESS_DEBUG 1 static Secp256k1 s_secp256k1;
Address dev::toAddress(Secret _secret) Public dev::toPublic(Secret const& _secret)
{ {
return KeyPair(_secret).address(); Public p;
s_secp256k1.toPublic(_secret, p);
return std::move(p);
} }
KeyPair KeyPair::create() Address dev::toAddress(Public const& _public)
{ {
static mt19937_64 s_eng(time(0) + chrono::high_resolution_clock::now().time_since_epoch().count()); return s_secp256k1.toAddress(_public);
uniform_int_distribution<uint16_t> d(0, 255);
for (int i = 0; i < 100; ++i)
{
h256 sec;
for (unsigned i = 0; i < 32; ++i)
sec[i] = (byte)d(s_eng);
KeyPair ret(sec);
if (ret.address())
return ret;
}
return KeyPair();
} }
KeyPair::KeyPair(h256 _sec): Address dev::toAddress(Secret const& _secret)
m_secret(_sec)
{ {
toPublic(m_secret, m_public); Public p;
if (verifySecret(m_secret, m_public)) s_secp256k1.toPublic(_secret, p);
m_address = right160(dev::sha3(m_public.ref())); return s_secp256k1.toAddress(p);
#if ETH_ADDRESS_DEBUG
cout << "---- ADDRESS -------------------------------" << endl;
cout << "SEC: " << m_secret << endl;
cout << "PUB: " << m_public << endl;
cout << "ADR: " << m_address << endl;
#endif
} }
KeyPair KeyPair::fromEncryptedSeed(bytesConstRef _seed, std::string const& _password) void dev::encrypt(Public const& _k, bytesConstRef _plain, bytes& o_cipher)
{
return KeyPair(sha3(aesDecrypt(_seed, _password)));
}
void dev::encrypt(Public _k, bytesConstRef _plain, bytes& o_cipher)
{ {
bytes io = _plain.toBytes(); bytes io = _plain.toBytes();
crypto::encrypt(_k, io); s_secp256k1.encrypt(_k, io);
o_cipher = std::move(io); o_cipher = std::move(io);
} }
bool dev::decrypt(Secret _k, bytesConstRef _cipher, bytes& o_plaintext) bool dev::decrypt(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext)
{ {
bytes io = _cipher.toBytes(); bytes io = _cipher.toBytes();
crypto::decrypt(_k, io); s_secp256k1.decrypt(_k, io);
if (io.empty()) if (io.empty())
return false; return false;
o_plaintext = std::move(io); o_plaintext = std::move(io);
return true; return true;
} }
Public dev::recover(Signature _sig, h256 _message) Public dev::recover(Signature const& _sig, h256 const& _message)
{
return s_secp256k1.recover(_sig, _message.ref());
}
Signature dev::sign(Secret const& _k, h256 const& _hash)
{
return s_secp256k1.sign(_k, _hash);
}
bool dev::verify(Public const& _p, Signature const& _s, h256 const& _hash)
{ {
return crypto::recover(_sig, _message.ref()); return s_secp256k1.verify(_p, _s, _hash.ref(), true);
} }
Signature dev::sign(Secret _k, h256 _hash) KeyPair KeyPair::create()
{ {
return crypto::sign(_k, _hash); static mt19937_64 s_eng(time(0) + chrono::high_resolution_clock::now().time_since_epoch().count());
uniform_int_distribution<uint16_t> d(0, 255);
for (int i = 0; i < 100; ++i)
{
KeyPair ret(FixedHash<32>::random(s_eng));
if (ret.address())
return ret;
}
return KeyPair();
} }
bool dev::verify(Public _p, Signature _s, h256 _hash) KeyPair::KeyPair(h256 _sec):
m_secret(_sec)
{
if (s_secp256k1.verifySecret(m_secret, m_public))
m_address = s_secp256k1.toAddress(m_public);
}
KeyPair KeyPair::fromEncryptedSeed(bytesConstRef _seed, std::string const& _password)
{ {
return crypto::verify(_p, _s, bytesConstRef(_hash.data(), 32), true); return KeyPair(sha3(aesDecrypt(_seed, _password)));
}
h256 crypto::kdf(Secret const& _priv, h256 const& _hash)
{
// H(H(r||k)^h)
h256 s;
sha3mac(Nonce::get().ref(), _priv.ref(), s.ref());
s ^= _hash;
sha3(s.ref(), s.ref());
if (!s || !_hash || !_priv)
BOOST_THROW_EXCEPTION(InvalidState());
return std::move(s);
} }
h256 Nonce::get(bool _commit) h256 Nonce::get(bool _commit)
@ -125,7 +140,7 @@ h256 Nonce::get(bool _commit)
else else
{ {
// todo: replace w/entropy from user and system // todo: replace w/entropy from user and system
std::mt19937_64 s_eng(time(0)); std::mt19937_64 s_eng(time(0) + chrono::high_resolution_clock::now().time_since_epoch().count());
std::uniform_int_distribution<uint16_t> d(0, 255); std::uniform_int_distribution<uint16_t> d(0, 255);
for (unsigned i = 0; i < 32; ++i) for (unsigned i = 0; i < 32; ++i)
s_seed[i] = (byte)d(s_eng); s_seed[i] = (byte)d(s_eng);

23
libdevcrypto/Common.h

@ -52,30 +52,36 @@ using Address = h160;
/// A vector of Ethereum addresses. /// A vector of Ethereum addresses.
using Addresses = h160s; using Addresses = h160s;
/// A vector of Ethereum addresses. /// A set of Ethereum addresses.
using AddressSet = std::set<h160>; using AddressSet = std::set<h160>;
/// A vector of secrets. /// A vector of secrets.
using Secrets = h256s; using Secrets = h256s;
/// Convert a secret key into the public key equivalent. /// Convert a secret key into the public key equivalent.
Public toPublic(Secret const& _secret);
/// Convert a public key to address.
Address toAddress(Public const& _public);
/// Convert a secret key into address of public key equivalent.
/// @returns 0 if it's not a valid secret key. /// @returns 0 if it's not a valid secret key.
Address toAddress(Secret _secret); Address toAddress(Secret const& _secret);
/// Encrypts plain text using Public key. /// Encrypts plain text using Public key.
void encrypt(Public _k, bytesConstRef _plain, bytes& o_cipher); void encrypt(Public const& _k, bytesConstRef _plain, bytes& o_cipher);
/// Decrypts cipher using Secret key. /// Decrypts cipher using Secret key.
bool decrypt(Secret _k, bytesConstRef _cipher, bytes& o_plaintext); bool decrypt(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext);
/// Recovers Public key from signed message hash. /// Recovers Public key from signed message hash.
Public recover(Signature _sig, h256 _hash); Public recover(Signature const& _sig, h256 const& _hash);
/// Returns siganture of message hash. /// Returns siganture of message hash.
Signature sign(Secret _k, h256 _hash); Signature sign(Secret const& _k, h256 const& _hash);
/// Verify signature. /// Verify signature.
bool verify(Public _k, Signature _s, h256 _hash); bool verify(Public const& _k, Signature const& _s, h256 const& _hash);
/// Simple class that represents a "key pair". /// Simple class that represents a "key pair".
/// All of the data of the class can be regenerated from the secret key (m_secret) alone. /// All of the data of the class can be regenerated from the secret key (m_secret) alone.
@ -119,6 +125,9 @@ namespace crypto
{ {
struct InvalidState: public dev::Exception {}; struct InvalidState: public dev::Exception {};
/// Key derivation
h256 kdf(Secret const& _priv, h256 const& _hash);
/** /**
* @brief Generator for nonce material * @brief Generator for nonce material
*/ */

199
libdevcrypto/CryptoPP.cpp

@ -21,25 +21,206 @@
#include "CryptoPP.h" #include "CryptoPP.h"
using namespace std;
using namespace dev; using namespace dev;
using namespace dev::crypto; using namespace dev::crypto;
using namespace CryptoPP; using namespace CryptoPP;
static_assert(dev::Secret::size == 32, "Secret key must be 32 bytes.");
static_assert(dev::Public::size == 64, "Public key must be 64 bytes.");
static_assert(dev::Signature::size == 65, "Signature must be 65 bytes.");
/// Integer and Point Conversion: void Secp256k1::encrypt(Public const& _k, bytes& io_cipher)
{
ECIES<ECP>::Encryptor e;
initializeDLScheme(_k, e);
size_t plen = io_cipher.size();
bytes ciphertext;
ciphertext.resize(e.CiphertextLength(plen));
{
lock_guard<mutex> l(x_rng);
e.Encrypt(m_rng, io_cipher.data(), plen, ciphertext.data());
}
memset(io_cipher.data(), 0, io_cipher.size());
io_cipher = std::move(ciphertext);
}
void Secp256k1::decrypt(Secret const& _k, bytes& io_text)
{
CryptoPP::ECIES<CryptoPP::ECP>::Decryptor d;
initializeDLScheme(_k, d);
size_t clen = io_text.size();
bytes plain;
plain.resize(d.MaxPlaintextLength(io_text.size()));
DecodingResult r;
{
lock_guard<mutex> l(x_rng);
r = d.Decrypt(m_rng, io_text.data(), clen, plain.data());
}
if (!r.isValidCoding)
{
io_text.clear();
return;
}
io_text.resize(r.messageLength);
io_text = std::move(plain);
}
Signature Secp256k1::sign(Secret const& _k, bytesConstRef _message)
{
return sign(_k, sha3(_message));
}
Signature Secp256k1::sign(Secret const& _key, h256 const& _hash)
{
// assumption made by signing alogrithm
asserts(m_q == m_qs);
Signature sig;
Integer k(kdf(_key, _hash).data(), 32);
if (k == 0)
BOOST_THROW_EXCEPTION(InvalidState());
k = 1 + (k % (m_qs - 1));
ECP::Point rp;
Integer r;
{
lock_guard<mutex> l(x_params);
rp = m_params.ExponentiateBase(k);
r = m_params.ConvertElementToInteger(rp);
}
sig[64] = 0;
// sig[64] = (r >= m_q) ? 2 : 0;
Integer kInv = k.InverseMod(m_q);
Integer z(_hash.asBytes().data(), 32);
Integer s = (kInv * (Integer(_key.asBytes().data(), 32)*r + z)) % m_q;
if (r == 0 || s == 0)
BOOST_THROW_EXCEPTION(InvalidState());
// if (s > m_qs)
// {
// s = m_q - s;
// if (sig[64])
// sig[64] ^= 1;
// }
sig[64] |= rp.y.IsOdd() ? 1 : 0;
r.Encode(sig.data(), 32);
s.Encode(sig.data() + 32, 32);
return sig;
}
bool Secp256k1::verify(Signature const& _signature, bytesConstRef _message)
{
return !!recover(_signature, _message);
}
void pp::exportPublicKey(CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> const& _k, Public& _p) bool Secp256k1::verify(Public const& _p, Signature const& _sig, bytesConstRef _message, bool _hashed)
{
// todo: verify w/o recovery (if faster)
return _p == _hashed ? recover(_sig, _message) : recover(_sig, sha3(_message).ref());
}
Public Secp256k1::recover(Signature _signature, bytesConstRef _message)
{
Public recovered;
Integer r(_signature.data(), 32);
Integer s(_signature.data()+32, 32);
// cryptopp encodes sign of y as 0x02/0x03 instead of 0/1 or 27/28
byte encodedpoint[33];
encodedpoint[0] = _signature[64]|2;
memcpy(&encodedpoint[1], _signature.data(), 32);
ECP::Element x;
{
lock_guard<mutex> l(x_curve);
m_curve.DecodePoint(x, encodedpoint, 33);
if (!m_curve.VerifyPoint(x))
return recovered;
}
// if (_signature[64] & 2)
// {
// r += m_q;
// lock_guard<mutex> l(x_params);
// if (r >= m_params.GetMaxExponent())
// return recovered;
// }
Integer z(_message.data(), 32);
Integer rn = r.InverseMod(m_q);
Integer u1 = m_q - (rn.Times(z)).Modulo(m_q);
Integer u2 = (rn.Times(s)).Modulo(m_q);
ECP::Point p;
byte recoveredbytes[65];
{
lock_guard<mutex> l(x_curve);
// todo: make generator member
p = m_curve.CascadeMultiply(u2, x, u1, m_params.GetSubgroupGenerator());
m_curve.EncodePoint(recoveredbytes, p, false);
}
memcpy(recovered.data(), &recoveredbytes[1], 64);
return recovered;
}
bool Secp256k1::verifySecret(Secret const& _s, Public& _p)
{
DL_PrivateKey_EC<ECP> k;
k.Initialize(m_params, secretToExponent(_s));
if (!k.Validate(m_rng, 3))
return false;
DL_PublicKey_EC<CryptoPP::ECP> pub;
k.MakePublicKey(pub);
if (!k.Validate(m_rng, 3))
return false;
exportPublicKey(pub, _p);
return true;
}
void Secp256k1::agree(Secret const& _s, Public const& _r, h256& o_s)
{
ECDH<ECP>::Domain d(m_oid);
assert(d.AgreedValueLength() == sizeof(o_s));
byte remote[65] = {0x04};
memcpy(&remote[1], _r.data(), 64);
assert(d.Agree(o_s.data(), _s.data(), remote));
}
void Secp256k1::exportPublicKey(CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> const& _k, Public& o_p)
{ {
bytes prefixedKey(_k.GetGroupParameters().GetEncodedElementSize(true)); bytes prefixedKey(_k.GetGroupParameters().GetEncodedElementSize(true));
secp256k1Params.GetCurve().EncodePoint(prefixedKey.data(), _k.GetPublicElement(), false);
{
lock_guard<mutex> l(x_params);
m_params.GetCurve().EncodePoint(prefixedKey.data(), _k.GetPublicElement(), false);
assert(Public::size + 1 == _k.GetGroupParameters().GetEncodedElementSize(true));
}
assert(Public::size + 1 == _k.GetGroupParameters().GetEncodedElementSize(true)); memcpy(o_p.data(), &prefixedKey[1], Public::size);
memcpy(_p.data(), &prefixedKey[1], Public::size);
} }
void pp::exponentToPublic(Integer const& _e, Public& _p) void Secp256k1::exponentToPublic(Integer const& _e, Public& o_p)
{ {
CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> pk; CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> pk;
pk.Initialize(secp256k1Params, secp256k1Params.ExponentiateBase(_e));
pp::exportPublicKey(pk, _p); {
} lock_guard<mutex> l(x_params);
pk.Initialize(m_params, m_params.ExponentiateBase(_e));
}
exportPublicKey(pk, o_p);
}

84
libdevcrypto/CryptoPP.h

@ -23,6 +23,7 @@
#pragma once #pragma once
#include <mutex>
// need to leave this one disabled for link-time. blame cryptopp. // need to leave this one disabled for link-time. blame cryptopp.
#pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wunused-function"
#pragma warning(push) #pragma warning(push)
@ -48,42 +49,85 @@
#include <dsa.h> #include <dsa.h>
#pragma warning(pop) #pragma warning(pop)
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#include "SHA3.h"
#include "Common.h" #include "Common.h"
namespace dev namespace dev
{ {
namespace crypto namespace crypto
{ {
namespace pp
{
using namespace CryptoPP; using namespace CryptoPP;
inline ECP::Point publicToPoint(Public const& _p) { Integer x(_p.data(), 32); Integer y(_p.data() + 32, 32); return std::move(ECP::Point(x,y)); }
inline Integer secretToExponent(Secret const& _s) { return std::move(Integer(_s.data(), Secret::size)); }
/**
* CryptoPP secp256k1 algorithms.
*/
class Secp256k1
{
public:
Secp256k1(): m_oid(ASN1::secp256k1()), m_params(m_oid), m_curve(m_params.GetCurve()), m_q(m_params.GetGroupOrder()), m_qs(m_params.GetSubgroupOrder()) {}
/// CryptoPP random number pool Address toAddress(Public const& _p) { return right160(sha3(_p.ref())); }
static CryptoPP::AutoSeededRandomPool PRNG;
/// CryptoPP EC Cruve void toPublic(Secret const& _s, Public& o_public) { exponentToPublic(Integer(_s.data(), sizeof(_s)), o_public); }
static const CryptoPP::OID secp256k1Curve = CryptoPP::ASN1::secp256k1();
static const CryptoPP::DL_GroupParameters_EC<CryptoPP::ECP> secp256k1Params(secp256k1Curve); /// Encrypts text (replace input).
void encrypt(Public const& _k, bytes& io_cipher);
static ECP::Point publicToPoint(Public const& _p) { Integer x(_p.data(), 32); Integer y(_p.data() + 32, 32); return std::move(ECP::Point(x,y)); } /// Decrypts text (replace input).
void decrypt(Secret const& _k, bytes& io_text);
static Integer secretToExponent(Secret const& _s) { return std::move(Integer(_s.data(), Secret::size)); } /// @returns siganture of message.
Signature sign(Secret const& _k, bytesConstRef _message);
void exportPublicKey(CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> const& _k, Public& _p);
/// @returns compact siganture of provided hash.
static void exportPrivateKey(CryptoPP::DL_PrivateKey_EC<CryptoPP::ECP> const& _k, Secret& _s) { _k.GetPrivateExponent().Encode(_s.data(), Secret::size); } Signature sign(Secret const& _k, h256 const& _hash);
/// Verify compact signature (public key is extracted from signature).
bool verify(Signature const& _signature, bytesConstRef _message);
/// Verify signature.
bool verify(Public const& _p, Signature const& _sig, bytesConstRef _message, bool _hashed = false);
void exponentToPublic(Integer const& _e, Public& _p); /// Recovers public key from compact signature. Uses libsecp256k1.
Public recover(Signature _signature, bytesConstRef _message);
template <class T> /// Verifies _s is a valid secret key and returns corresponding public key in o_p.
void initializeDLScheme(Secret const& _s, T& io_operator) { io_operator.AccessKey().Initialize(pp::secp256k1Params, secretToExponent(_s)); } bool verifySecret(Secret const& _s, Public& o_p);
template <class T> void agree(Secret const& _s, Public const& _r, h256& o_s);
void initializeDLScheme(Public const& _p, T& io_operator) { io_operator.AccessKey().Initialize(pp::secp256k1Params, publicToPoint(_p)); }
protected:
void exportPrivateKey(DL_PrivateKey_EC<ECP> const& _k, Secret& o_s) { _k.GetPrivateExponent().Encode(o_s.data(), Secret::size); }
void exportPublicKey(DL_PublicKey_EC<ECP> const& _k, Public& o_p);
void exponentToPublic(Integer const& _e, Public& o_p);
template <class T> void initializeDLScheme(Secret const& _s, T& io_operator) { std::lock_guard<std::mutex> l(x_params); io_operator.AccessKey().Initialize(m_params, secretToExponent(_s)); }
template <class T> void initializeDLScheme(Public const& _p, T& io_operator) { std::lock_guard<std::mutex> l(x_params); io_operator.AccessKey().Initialize(m_params, publicToPoint(_p)); }
private:
OID m_oid;
std::mutex x_rng;
AutoSeededRandomPool m_rng;
std::mutex x_params;
DL_GroupParameters_EC<ECP> m_params;
std::mutex x_curve;
DL_GroupParameters_EC<ECP>::EllipticCurve m_curve;
Integer m_q;
Integer m_qs;
};
} }
} }
}

202
libdevcrypto/EC.cpp

@ -1,202 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file EC.cpp
* @author Alex Leverington <nessence@gmail.com>
* @date 2014
*
* ECDSA, ECIES
*/
#include <secp256k1/secp256k1.h>
#include "CryptoPP.h"
#include "SHA3.h"
#include "SHA3MAC.h"
#include "EC.h"
static_assert(dev::Secret::size == 32, "Secret key must be 32 bytes.");
static_assert(dev::Public::size == 64, "Public key must be 64 bytes.");
static_assert(dev::Signature::size == 65, "Signature must be 65 bytes.");
using namespace std;
using namespace dev;
using namespace dev::crypto;
using namespace CryptoPP;
using namespace pp;
static const int c_publicKeySize = 65; // Public key size for I/O is 65 bytes (there's an extra byte that we don't really need).
void crypto::toPublic(Secret const& _s, Public& o_public)
{
exponentToPublic(Integer(_s.data(), sizeof(_s)), o_public);
}
h256 crypto::kdf(Secret const& _priv, h256 const& _hash)
{
// H(H(r||k)^h)
h256 s;
sha3mac(Nonce::get().ref(), _priv.ref(), s.ref());
s ^= _hash;
sha3(s.ref(), s.ref());
if (!s || !_hash || !_priv)
BOOST_THROW_EXCEPTION(InvalidState());
return std::move(s);
}
void crypto::encrypt(Public const& _k, bytes& io_cipher)
{
ECIES<ECP>::Encryptor e;
initializeDLScheme(_k, e);
size_t plen = io_cipher.size();
bytes c;
c.resize(e.CiphertextLength(plen));
// todo: use StringSource with io_cipher as input and output.
e.Encrypt(PRNG, io_cipher.data(), plen, c.data());
memset(io_cipher.data(), 0, io_cipher.size());
io_cipher = std::move(c);
}
void crypto::decrypt(Secret const& _k, bytes& io_text)
{
CryptoPP::ECIES<CryptoPP::ECP>::Decryptor d;
initializeDLScheme(_k, d);
size_t clen = io_text.size();
bytes p;
p.resize(d.MaxPlaintextLength(io_text.size()));
// todo: use StringSource with io_text as input and output.
DecodingResult r = d.Decrypt(PRNG, io_text.data(), clen, p.data());
if (!r.isValidCoding)
{
io_text.clear();
return;
}
io_text.resize(r.messageLength);
io_text = std::move(p);
}
Signature crypto::sign(Secret const& _k, bytesConstRef _message)
{
return crypto::sign(_k, sha3(_message));
}
Signature crypto::sign(Secret const& _key, h256 const& _hash)
{
ECDSA<ECP,SHA3_256>::Signer signer;
initializeDLScheme(_key, signer);
Integer const& q = secp256k1Params.GetGroupOrder();
Integer const& qs = secp256k1Params.GetSubgroupOrder();
Integer e(_hash.asBytes().data(), 32);
Integer k(kdf(_key, _hash).data(), 32);
if (k == 0)
BOOST_THROW_EXCEPTION(InvalidState());
k = 1 + (k % (qs - 1));
ECP::Point rp = secp256k1Params.ExponentiateBase(k);
Integer r = secp256k1Params.ConvertElementToInteger(rp);
int recid = ((r >= q) ? 2 : 0) | (rp.y.IsOdd() ? 1 : 0);
Integer kInv = k.InverseMod(q);
Integer s = (kInv * (Integer(_key.asBytes().data(), 32)*r + e)) % q;
assert(!!r && !!s);
if (s > qs)
{
s = q - s;
if (recid)
recid ^= 1;
}
Signature sig;
r.Encode(sig.data(), 32);
s.Encode(sig.data() + 32, 32);
sig[64] = recid;
return sig;
}
bool crypto::verify(Signature const& _signature, bytesConstRef _message)
{
return crypto::verify(crypto::recover(_signature, _message), _signature, _message);
}
bool crypto::verify(Public const& _p, Signature const& _sig, bytesConstRef _message, bool _hashed)
{
static const size_t c_derMaxEncodingLength = 72;
if (_hashed)
{
assert(_message.size() == 32);
byte encpub[65] = {0x04};
memcpy(&encpub[1], _p.data(), 64);
byte dersig[c_derMaxEncodingLength];
size_t cssz = DSAConvertSignatureFormat(dersig, c_derMaxEncodingLength, DSA_DER, _sig.data(), 64, DSA_P1363);
assert(cssz <= c_derMaxEncodingLength);
return (1 == secp256k1_ecdsa_verify(_message.data(), _message.size(), dersig, cssz, encpub, c_publicKeySize));
}
ECDSA<ECP, SHA3_256>::Verifier verifier;
initializeDLScheme(_p, verifier);
return verifier.VerifyMessage(_message.data(), _message.size(), _sig.data(), sizeof(Signature) - 1);
}
Public crypto::recover(Signature _signature, bytesConstRef _message)
{
secp256k1_start();
byte pubkey[c_publicKeySize];
int keySize;
if (!secp256k1_ecdsa_recover_compact(_message.data(), 32, _signature.data(), pubkey, &keySize, 0, (int)_signature[64]) || keySize != c_publicKeySize)
return Public();
#if ETH_CRYPTO_TRACE
h256* sig = (h256 const*)_signature.data();
cout << "---- RECOVER -------------------------------" << endl;
cout << "MSG: " << _message << endl;
cout << "R S V: " << sig[0] << " " << sig[1] << " " << (int)(_signature[64] - 27) << "+27" << endl;
cout << "PUB: " << toHex(bytesConstRef(&(pubkey[1]), 64)) << endl;
#endif
Public ret;
memcpy(&ret, &(pubkey[1]), sizeof(Public));
return ret;
}
bool crypto::verifySecret(Secret const& _s, Public const& _p)
{
secp256k1_start();
int ok = secp256k1_ecdsa_seckey_verify(_s.data());
if (!ok)
return false;
byte pubkey[c_publicKeySize];
int keySize;
ok = secp256k1_ecdsa_pubkey_create(pubkey, &keySize, _s.data(), 0);
if (!ok || keySize != c_publicKeySize)
return false;
ok = secp256k1_ecdsa_pubkey_verify(pubkey, c_publicKeySize);
if (!ok)
return false;
for (int i = 0; i < 32; i++)
if (pubkey[i+1]!=_p[i])
return false;
return true;
}

62
libdevcrypto/EC.h

@ -1,62 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file EC.h
* @author Alex Leverington <nessence@gmail.com>
* @date 2014
*
* ECDSA, ECIES
*/
#pragma once
#include "Common.h"
namespace dev
{
namespace crypto
{
void toPublic(Secret const& _s, Public& o_public);
h256 kdf(Secret const& _priv, h256 const& _hash);
/// Encrypts text (in place).
void encrypt(Public const& _k, bytes& io_cipher);
/// Decrypts text (in place).
void decrypt(Secret const& _k, bytes& io_text);
/// Returns siganture of message.
Signature sign(Secret const& _k, bytesConstRef _message);
/// Returns compact siganture of message hash.
Signature sign(Secret const& _k, h256 const& _hash);
/// Verify compact signature (public key is extracted from message).
bool verify(Signature const& _signature, bytesConstRef _message);
/// Verify signature.
bool verify(Public const& _p, Signature const& _sig, bytesConstRef _message, bool _hashed = false);
/// Recovers public key from compact signature. Uses libsecp256k1.
Public recover(Signature _signature, bytesConstRef _message);
bool verifySecret(Secret const& _s, Public const& _p);
}
}

100
libdevcrypto/ECDHE.cpp

@ -0,0 +1,100 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ECDHE.cpp
* @author Alex Leverington <nessence@gmail.com>
* @date 2014
*/
#include "SHA3.h"
#include "CryptoPP.h"
#include "ECDHE.h"
using namespace std;
using namespace dev;
using namespace dev::crypto;
static Secp256k1 s_secp256k1;
void ECDHE::agree(Public const& _remote, Secret& o_sharedSecret)
{
if (m_remoteEphemeral)
// agreement can only occur once
BOOST_THROW_EXCEPTION(InvalidState());
m_remoteEphemeral = _remote;
s_secp256k1.agree(m_ephemeral.sec(), m_remoteEphemeral, o_sharedSecret);
}
void ECDHEKeyExchange::agree(Public const& _remoteEphemeral)
{
s_secp256k1.agree(m_ephemeral.sec(), _remoteEphemeral, m_ephemeralSecret);
}
void ECDHEKeyExchange::exchange(bytes& o_exchange)
{
if (!m_ephemeralSecret)
// didn't agree on public remote
BOOST_THROW_EXCEPTION(InvalidState());
// The key exchange payload is in two parts and is encrypted
// using ephemeral keypair.
//
// The first part is the 'prefix' which is a zero-knowledge proof
// allowing the remote to resume or emplace a previous session.
// If a session previously exists:
// prefix is sha3(token) // todo: ephemeral entropy from both sides
// If a session doesn't exist:
// prefix is sha3(m_ephemeralSecret)
//
// The second part is encrypted using the public key which relates to the prefix.
Public encpk = m_known.first ? m_known.first : m_remoteEphemeral;
bytes exchange(encpk.asBytes());
// This is the public key which we would like the remote to use,
// which maybe different than the previously-known public key.
//
// Here we should pick an appropriate alias or generate a new one,
// but for now, we use static alias passed to constructor.
//
Public p = toPublic(m_alias.m_secret);
exchange.resize(exchange.size() + sizeof(p));
memcpy(&exchange[exchange.size() - sizeof(p)], p.data(), sizeof(p));
// protocol parameters; should be fixed size
bytes v(1, 0x80);
exchange.resize(exchange.size() + v.size());
memcpy(&exchange[exchange.size() - v.size()], v.data(), v.size());
h256 auth;
sha3mac(m_alias.m_secret.ref(), m_ephemeralSecret.ref(), auth.ref());
Signature sig = s_secp256k1.sign(m_alias.m_secret, auth);
exchange.resize(exchange.size() + sizeof(sig));
memcpy(&exchange[exchange.size() - sizeof(sig)], sig.data(), sizeof(sig));
aes::AuthenticatedStream aes(aes::Encrypt, m_ephemeralSecret, 0);
h256 prefix(sha3(m_known.second ? m_known.second : (h256)m_remoteEphemeral));
aes.update(prefix.ref());
s_secp256k1.encrypt(encpk, exchange);
aes.update(&exchange);
aes.streamOut(o_exchange);
}

109
libdevcrypto/ECDHE.h

@ -0,0 +1,109 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ECDHE.h
* @author Alex Leverington <nessence@gmail.com>
* @date 2014
*
* Elliptic curve Diffie-Hellman ephemeral key exchange
*/
#pragma once
#include "AES.h"
namespace dev
{
namespace crypto
{
/// Public key of remote and corresponding shared secret.
typedef std::pair<Public,h256> AliasSession;
/**
* @brief An addressable EC key pair.
*/
class Alias
{
friend class ECDHEKeyExchange; // todo: remove
public:
Alias(Secret _s): m_secret(_s) {};
AliasSession session(Address _a) { return m_sessions.count(_a) ? m_sessions.find(_a)->second : AliasSession(); }
private:
std::map<Address,AliasSession> m_sessions;
Secret m_secret;
};
/**
* @brief Derive DH shared secret from EC keypairs.
* As ephemeral keys are single-use, agreement is limited to a single occurence.
*/
class ECDHE
{
public:
/// Constructor (pass public key for ingress exchange).
ECDHE(): m_ephemeral(KeyPair::create()) {};
/// Public key sent to remote.
Public pubkey() { return m_ephemeral.pub(); }
/// Input public key for dh agreement, output generated shared secret.
void agree(Public const& _remoteEphemeral, Secret& o_sharedSecret);
protected:
KeyPair m_ephemeral; ///< Ephemeral keypair; generated.
Public m_remoteEphemeral; ///< Public key of remote; parameter.
};
/**
* @brief Secure exchange of static keys.
* Key exchange is encrypted with public key of remote and then encrypted by block cipher. For a blind remote the ecdhe public key is used to encrypt exchange, and for a known remote the known public key is used. The block cipher key is derived from ecdhe shared secret.
*
* Usage: Agree -> Exchange -> Authenticate
*/
class ECDHEKeyExchange: private ECDHE
{
public:
/// Exchange with unknown remote (pass public key for ingress exchange)
ECDHEKeyExchange(Alias& _k): m_alias(_k) {};
/// Exchange with known remote
ECDHEKeyExchange(Alias& _k, AliasSession _known): m_alias(_k), m_known(_known) {};
/// Provide public key for dh agreement to generate shared secret.
void agree(Public const& _remoteEphemeral);
/// @returns encrypted payload of key exchange
void exchange(bytes& o_exchange);
/// Decrypt payload, check mac, check trust, decrypt exchange, authenticate exchange, verify version, verify signature, and if no failure occurs, update or creats trust and derive session-shared-secret.
bool authenticate(bytes _exchangeIn);
private:
Secret m_ephemeralSecret;
Alias m_alias;
AliasSession m_known;
Secret m_sharedAliasSecret;
FixedHash<16> m_sharedC;
FixedHash<16> m_sharedM;
};
}
}

10
libdevcrypto/SHA3.cpp

@ -86,6 +86,16 @@ h256 sha3(bytesConstRef _input)
sha3(_input, bytesRef(&ret[0], 32)); sha3(_input, bytesRef(&ret[0], 32));
return ret; return ret;
} }
void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output)
{
CryptoPP::SHA3_256 ctx;
assert(_secret.size() > 0);
ctx.Update((byte*)_secret.data(), _secret.size());
ctx.Update((byte*)_plain.data(), _plain.size());
assert(_output.size() >= 32);
ctx.Final(_output.data());
}
bytes aesDecrypt(bytesConstRef _ivCipher, std::string const& _password, unsigned _rounds, bytesConstRef _salt) bytes aesDecrypt(bytesConstRef _ivCipher, std::string const& _password, unsigned _rounds, bytesConstRef _salt)
{ {

3
libdevcrypto/SHA3.h

@ -55,6 +55,9 @@ inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef((bytes*)&_inpu
/// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash. /// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash.
inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); } inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); }
/// Calculate SHA3-256 MAC
void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output);
/// Calculate SHA3-256 hash of the given input (presented as a FixedHash), returns a 256-bit hash. /// Calculate SHA3-256 hash of the given input (presented as a FixedHash), returns a 256-bit hash.
template<unsigned N> inline h256 sha3(FixedHash<N> const& _input) { return sha3(_input.ref()); } template<unsigned N> inline h256 sha3(FixedHash<N> const& _input) { return sha3(_input.ref()); }

38
libdevcrypto/SHA3MAC.h

@ -1,38 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file SHA3MAC.h
* @author Alex Leverington <nessence@gmail.com>
* @date 2014
*
* SHA3 MAC
*/
#pragma once
#include <libdevcore/Common.h>
#include <libdevcore/FixedHash.h>
namespace dev
{
namespace crypto
{
void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output);
}
}

27
libethcore/CommonEth.cpp

@ -28,7 +28,6 @@ using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
//#define ETH_ADDRESS_DEBUG 1
namespace dev namespace dev
{ {
namespace eth namespace eth
@ -84,30 +83,4 @@ std::string formatBalance(u256 _b)
return ret.str(); return ret.str();
} }
Address toAddress(Secret _private)
{
secp256k1_start();
byte pubkey[65];
int pubkeylen = 65;
int ok = secp256k1_ecdsa_seckey_verify(_private.data());
if (!ok)
return Address();
ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, _private.data(), 0);
assert(pubkeylen == 65);
if (!ok)
return Address();
ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65);
if (!ok)
return Address();
auto ret = right160(dev::sha3(bytesConstRef(&(pubkey[1]), 64)));
#if ETH_ADDRESS_DEBUG
cout << "---- ADDRESS -------------------------------" << endl;
cout << "SEC: " << _private << endl;
cout << "PUB: " << toHex(bytesConstRef(&(pubkey[1]), 64)) << endl;
cout << "ADR: " << ret << endl;
#endif
return ret;
}
}} }}

36
libethcore/CryptoHeaders.h

@ -1,36 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file CryptoHeaders.h
* @author Tim Hughes <tim@twistedfury.com>
* @date 2014
*/
#pragma once
// need to leave this one disabled
#pragma GCC diagnostic ignored "-Wunused-function"
#pragma warning(push)
#pragma warning(disable:4100 4244)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include <sha.h>
#include <sha3.h>
#include <ripemd.h>
#include <secp256k1/secp256k1.h>
#pragma warning(pop)
#pragma GCC diagnostic pop

6
libethereum/Executive.cpp

@ -71,7 +71,7 @@ bool Executive::setup(bytesConstRef _rlp)
if (m_t.gas() < gasCost) if (m_t.gas() < gasCost)
{ {
clog(StateDetail) << "Not enough gas to pay for the transaction: Require >" << gasCost << " Got" << m_t.gas(); clog(StateDetail) << "Not enough gas to pay for the transaction: Require >" << gasCost << " Got" << m_t.gas();
BOOST_THROW_EXCEPTION(OutOfGas()); BOOST_THROW_EXCEPTION(OutOfGas() << RequirementError((bigint)gasCost, (bigint)m_t.gas()));
} }
u256 cost = m_t.value() + m_t.gas() * m_t.gasPrice(); u256 cost = m_t.value() + m_t.gas() * m_t.gasPrice();
@ -80,14 +80,14 @@ bool Executive::setup(bytesConstRef _rlp)
if (m_s.balance(m_sender) < cost) if (m_s.balance(m_sender) < cost)
{ {
clog(StateDetail) << "Not enough cash: Require >" << cost << " Got" << m_s.balance(m_sender); clog(StateDetail) << "Not enough cash: Require >" << cost << " Got" << m_s.balance(m_sender);
BOOST_THROW_EXCEPTION(NotEnoughCash() << RequirementError((int)cost, (int)m_s.balance(m_sender))); BOOST_THROW_EXCEPTION(NotEnoughCash() << RequirementError((bigint)cost, (bigint)m_s.balance(m_sender)));
} }
u256 startGasUsed = m_s.gasUsed(); u256 startGasUsed = m_s.gasUsed();
if (startGasUsed + m_t.gas() > m_s.m_currentBlock.gasLimit) if (startGasUsed + m_t.gas() > m_s.m_currentBlock.gasLimit)
{ {
clog(StateDetail) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas(); clog(StateDetail) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas();
BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((int)(m_s.m_currentBlock.gasLimit - startGasUsed), (int)m_t.gas())); BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit - startGasUsed), (bigint)m_t.gas()));
} }
// Increment associated nonce for sender. // Increment associated nonce for sender.

10
libethereum/State.cpp

@ -114,8 +114,6 @@ State::State(Address _coinbaseAddress, OverlayDB const& _db):
m_ourAddress(_coinbaseAddress), m_ourAddress(_coinbaseAddress),
m_blockReward(c_blockReward) m_blockReward(c_blockReward)
{ {
secp256k1_start();
// Initialise to the state entailed by the genesis block; this guarantees the trie is built correctly. // Initialise to the state entailed by the genesis block; this guarantees the trie is built correctly.
m_state.init(); m_state.init();
@ -139,8 +137,6 @@ State::State(OverlayDB const& _db, BlockChain const& _bc, h256 _h):
m_state(&m_db), m_state(&m_db),
m_blockReward(c_blockReward) m_blockReward(c_blockReward)
{ {
secp256k1_start();
// TODO THINK: is this necessary? // TODO THINK: is this necessary?
m_state.init(); m_state.init();
@ -328,8 +324,8 @@ StateDiff State::diff(State const& _c) const
for (auto i: _c.m_cache) for (auto i: _c.m_cache)
ads.insert(i.first); ads.insert(i.first);
cnote << *this; // cnote << *this;
cnote << _c; // cnote << _c;
for (auto i: ads) for (auto i: ads)
{ {
@ -797,8 +793,6 @@ h256 State::oldBloom() const
LogBloom State::logBloom() const LogBloom State::logBloom() const
{ {
LogBloom ret; LogBloom ret;
auto sa = sha3(m_currentBlock.coinbaseAddress.ref());
ret.shiftBloom<3>(sa);
for (TransactionReceipt const& i: m_receipts) for (TransactionReceipt const& i: m_receipts)
ret |= i.bloom(); ret |= i.bloom();
return ret; return ret;

2
libevm/VM.h

@ -45,7 +45,7 @@ public:
virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final;
void require(u256 _n) { if (m_stack.size() < _n) BOOST_THROW_EXCEPTION(StackTooSmall() << RequirementError(int(_n), m_stack.size())); } void require(u256 _n) { if (m_stack.size() < _n) BOOST_THROW_EXCEPTION(StackTooSmall() << RequirementError((bigint)_n, (bigint)m_stack.size())); }
void requireMem(unsigned _n) { if (m_temp.size() < _n) { m_temp.resize(_n); } } void requireMem(unsigned _n) { if (m_temp.size() < _n) { m_temp.resize(_n); } }
u256 curPC() const { return m_curPC; } u256 curPC() const { return m_curPC; }

10
libp2p/Host.cpp

@ -385,8 +385,8 @@ void Host::populateAddresses()
shared_ptr<Node> Host::noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId) shared_ptr<Node> Host::noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId)
{ {
RecursiveGuard l(x_peers); RecursiveGuard l(x_peers);
if (_a.port() < 30300 || _a.port() > 30303) if (_a.port() < 30300 || _a.port() > 30305)
cwarn << "Wierd port being recorded!"; cwarn << "Weird port being recorded: " << _a.port();
if (_a.port() >= /*49152*/32768) if (_a.port() >= /*49152*/32768)
{ {
@ -778,7 +778,7 @@ bytes Host::saveNodes() const
{ {
Node const& n = *(i.second); Node const& n = *(i.second);
// TODO: PoC-7: Figure out why it ever shares these ports.//n.address.port() >= 30300 && n.address.port() <= 30305 && // TODO: PoC-7: Figure out why it ever shares these ports.//n.address.port() >= 30300 && n.address.port() <= 30305 &&
if (!n.dead && n.address.port() > 0 && n.address.port() < /*49152*/32768 && n.id != id() && !isPrivateAddress(n.address.address())) if (!n.dead && chrono::system_clock::now() - n.lastConnected < chrono::seconds(3600 * 48) && n.address.port() > 0 && n.address.port() < /*49152*/32768 && n.id != id() && !isPrivateAddress(n.address.address()))
{ {
nodes.appendList(10); nodes.appendList(10);
if (n.address.address().is_v4()) if (n.address.address().is_v4())
@ -786,8 +786,8 @@ bytes Host::saveNodes() const
else else
nodes << n.address.address().to_v6().to_bytes(); nodes << n.address.address().to_v6().to_bytes();
nodes << n.address.port() << n.id << (int)n.idOrigin nodes << n.address.port() << n.id << (int)n.idOrigin
<< std::chrono::duration_cast<std::chrono::seconds>(n.lastConnected.time_since_epoch()).count() << chrono::duration_cast<chrono::seconds>(n.lastConnected.time_since_epoch()).count()
<< std::chrono::duration_cast<std::chrono::seconds>(n.lastAttempted.time_since_epoch()).count() << chrono::duration_cast<chrono::seconds>(n.lastAttempted.time_since_epoch()).count()
<< n.failedAttempts << (unsigned)n.lastDisconnect << n.score << n.rating; << n.failedAttempts << (unsigned)n.lastDisconnect << n.score << n.rating;
count++; count++;
} }

1
libqethereum/QEthereum.h

@ -83,6 +83,7 @@ private:
{ \ { \
_frame->disconnect(); \ _frame->disconnect(); \
_frame->addToJavaScriptWindowObject("_web3", qweb, QWebFrame::ScriptOwnership); \ _frame->addToJavaScriptWindowObject("_web3", qweb, QWebFrame::ScriptOwnership); \
_frame->addToJavaScriptWindowObject("env", _env, QWebFrame::QtOwnership); \
_frame->evaluateJavaScript(contentsOfQResource(":/js/es6-promise-2.0.0.js")); \ _frame->evaluateJavaScript(contentsOfQResource(":/js/es6-promise-2.0.0.js")); \
_frame->evaluateJavaScript(contentsOfQResource(":/js/main.js")); \ _frame->evaluateJavaScript(contentsOfQResource(":/js/main.js")); \
_frame->evaluateJavaScript(contentsOfQResource(":/js/qt.js")); \ _frame->evaluateJavaScript(contentsOfQResource(":/js/qt.js")); \

14
libweb3jsonrpc/WebThreeStubServer.cpp

@ -240,7 +240,7 @@ static shh::Envelope toSealed(Json::Value const& _json, shh::Message const& _m,
static pair<shh::TopicMask, Public> toWatch(Json::Value const& _json) static pair<shh::TopicMask, Public> toWatch(Json::Value const& _json)
{ {
shh::BuildTopicMask bt(shh::BuildTopicMask::Empty); shh::BuildTopicMask bt;
Public to; Public to;
if (!_json["to"].empty()) if (!_json["to"].empty())
@ -252,12 +252,8 @@ static pair<shh::TopicMask, Public> toWatch(Json::Value const& _json)
bt.shift(jsToBytes(_json["topic"].asString())); bt.shift(jsToBytes(_json["topic"].asString()));
else if (_json["topic"].isArray()) else if (_json["topic"].isArray())
for (auto i: _json["topic"]) for (auto i: _json["topic"])
{
if (i.isString()) if (i.isString())
bt.shift(jsToBytes(i.asString())); bt.shift(jsToBytes(i.asString()));
else
bt.shift();
}
} }
return make_pair(bt.toTopicMask(), to); return make_pair(bt.toTopicMask(), to);
} }
@ -374,10 +370,10 @@ static TransactionSkeleton toTransaction(Json::Value const& _json)
ret.data = jsToBytes(_json["code"].asString()); ret.data = jsToBytes(_json["code"].asString());
else if (_json["data"].isArray()) else if (_json["data"].isArray())
for (auto i: _json["data"]) for (auto i: _json["data"])
dev::operator +=(ret.data, jsToBytes(jsPadded(i.asString(), 32))); dev::operator +=(ret.data, padded(jsToBytes(i.asString()), 32));
else if (_json["code"].isArray()) else if (_json["code"].isArray())
for (auto i: _json["code"]) for (auto i: _json["code"])
dev::operator +=(ret.data, jsToBytes(jsPadded(i.asString(), 32))); dev::operator +=(ret.data, padded(jsToBytes(i.asString()), 32));
else if (_json["dataclose"].isArray()) else if (_json["dataclose"].isArray())
for (auto i: _json["dataclose"]) for (auto i: _json["dataclose"])
dev::operator +=(ret.data, jsToBytes(i.asString())); dev::operator +=(ret.data, jsToBytes(i.asString()));
@ -511,7 +507,7 @@ std::string WebThreeStubServer::shh_newGroup(std::string const& _id, std::string
std::string WebThreeStubServer::shh_newIdentity() std::string WebThreeStubServer::shh_newIdentity()
{ {
cnote << this << m_ids; // cnote << this << m_ids;
KeyPair kp = KeyPair::create(); KeyPair kp = KeyPair::create();
m_ids[kp.pub()] = kp.secret(); m_ids[kp.pub()] = kp.secret();
return toJS(kp.pub()); return toJS(kp.pub());
@ -539,7 +535,7 @@ int WebThreeStubServer::eth_peerCount()
bool WebThreeStubServer::shh_post(Json::Value const& _json) bool WebThreeStubServer::shh_post(Json::Value const& _json)
{ {
cnote << this << m_ids; // cnote << this << m_ids;
shh::Message m = toMessage(_json); shh::Message m = toMessage(_json);
Secret from; Secret from;

2
libwhisper/Common.cpp

@ -69,7 +69,7 @@ TopicMask BuildTopicMask::toTopicMask() const
TopicMask ret; TopicMask ret;
ret.reserve(m_parts.size()); ret.reserve(m_parts.size());
for (auto const& h: m_parts) for (auto const& h: m_parts)
ret.push_back(make_pair(TopicPart(h), h ? ~TopicPart() : TopicPart())); ret.push_back(make_pair(TopicPart(h), ~TopicPart()));
return ret; return ret;
} }

7
libwhisper/Common.h

@ -114,17 +114,12 @@ private:
class BuildTopicMask: BuildTopic class BuildTopicMask: BuildTopic
{ {
public: public:
enum EmptyType { Empty }; BuildTopicMask() {}
BuildTopicMask() { shift(); }
BuildTopicMask(EmptyType) {}
template <class T> BuildTopicMask(T const& _t) { shift(_t); } template <class T> BuildTopicMask(T const& _t) { shift(_t); }
template <class T> BuildTopicMask& shift(T const& _r) { BuildTopic::shift(_r); return *this; } template <class T> BuildTopicMask& shift(T const& _r) { BuildTopic::shift(_r); return *this; }
BuildTopicMask& shiftRaw(h256 const& _h) { BuildTopic::shiftRaw(_h); return *this; } BuildTopicMask& shiftRaw(h256 const& _h) { BuildTopic::shiftRaw(_h); return *this; }
BuildTopic& shift() { m_parts.push_back(h256()); return *this; }
BuildTopicMask& operator()() { shift(); return *this; }
template <class T> BuildTopicMask& operator()(T const& _t) { shift(_t); return *this; } template <class T> BuildTopicMask& operator()(T const& _t) { shift(_t); return *this; }
operator TopicMask() const { return toTopicMask(); } operator TopicMask() const { return toTopicMask(); }

326
stdserv.js

@ -1,67 +1,41 @@
eth = web3.eth; var compile = function(name) { return web3.eth.lll(env.contents("../../dapp-bin/" + name + "/" + name + ".lll")); };
var create = function(code) { return web3.eth.transact({ 'code': code }); };
env.note('Creating Config...') var send = function(from, val, to) { return web3.eth.transact({ 'from': from, 'value': val, 'to': to }); };
var configCode = eth.lll(" var initService = function(name, index, dep) { return dep.then(function(){ var ret = compile(name).then(create); register(ret, index); return ret; }); };
{
[[69]] (caller) var config = compile("config").then(create);
(returnlll { var register = function(address, index) { return web3.eth.transact({ 'to': config, 'gas': '10000', 'data': [index + '', address] }); };
(when (&& (= (calldatasize) 64) (= (caller) @@69)) var nameReg = initService("namereg", 0, config);
(for {} (< @i (calldatasize)) [i](+ @i 64) var regName = function(account, name) { return web3.eth.transact({ 'from': account, 'to': nameReg, 'gas': '10000', 'data': [ web3.fromAscii('register'), web3.fromAscii(name) ] }); };
[[ (calldataload @i) ]] (calldataload (+ @i 32)) var coins = initService("coins", 1, nameReg);
) var coin = initService("coin", 2, coins);
) var approve = function(account, approvedAddress) { web3.eth.transact({ 'from': account, 'to': coin, 'gas': '10000', 'data': [ web3.fromAscii('approve'), approvedAddress ] }); };
(return @@ $0) var exchange = initService("exchange", 3, coin);
}) var offer = function(account, haveCoin, haveVal, wantCoin, wantVal) { web3.eth.transact({ 'from': account, 'to': exchange, 'gas': '10000', 'data': [web3.fromAscii('new'), haveCoin, haveVal, wantCoin, wantVal] }); };
}
") config.then(function() {
env.note('Config code: ' + configCode) web3.eth.accounts.then(function(accounts)
var config; {
eth.transact({ 'code': configCode }, function(a) { config = a; }); var funded = send(accounts[0], '100000000000000000000', accounts[1]);
funded.then(function(){ env.note("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); regName(accounts[1], 'Gav Would'); env.note("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); approve(accounts[1], exchange); });
env.note('Config at address ' + config) regName(accounts[0], 'Gav');
approve(accounts[0], exchange).then(function(){ offer(accounts[0], coin, '5000', '0', '5000000000000000000'); });
var nameRegCode = eth.lll("
{ // TODO: once we have a new implementation of DNSReg.
[[(address)]] 'NameReg // env.note('Register gav.eth...')
[['NameReg]] (address) // eth.transact({ 'to': dnsReg, 'data': [web3.fromAscii('register'), web3.fromAscii('gav'), web3.fromAscii('opensecrecy.com')] });
[[config]] 'Config });
[['Config]] config });
[[69]] (caller)
(returnlll { // TODO
(when (= $0 'register) { /*
(when @@ $32 (stop))
(when @@(caller) [[@@(caller)]] 0)
[[$32]] (caller)
[[(caller)]] $32
(stop)
})
(when (&& (= $0 'unregister) @@(caller)) {
[[@@(caller)]] 0
[[(caller)]] 0
(stop)
})
(when (&& (= $0 'kill) (= (caller) @@69)) (suicide (caller)))
(return @@ $0)
})
}
");
env.note('NameReg code: ' + nameRegCode)
var nameReg;
env.note('Create NameReg...')
eth.transact({ 'code': nameRegCode }, function(a) { nameReg = a; });
env.note('Register NameReg...')
eth.transact({ 'to': config, 'data': ['0', nameReg] });
var nameRegJeff; var nameRegJeff;
env.note('Create NameRegJeff...') env.note('Create NameRegJeff...')
eth.transact({ 'code': nameRegCode }, function(a) { nameRegJeff = a; }); eth.transact({ 'code': nameRegCode }, function(a) { nameRegJeff = a; });
env.note('Register NameRegJeff...') env.note('Register NameRegJeff...')
eth.transact({ 'to': config, 'data': ['4', nameReg] }); eth.transact({ 'to': config, 'data': ['4', nameRegJeff] });
var dnsRegCode = '0x60006000546000600053602001546000600053604001546020604060206020600073661005d2720d855f1d9976f88bb10c1a3398c77f6103e8f17f7265676973746572000000000000000000000000000000000000000000000000600053606001600060200201547f446e735265670000000000000000000000000000000000000000000000000000600053606001600160200201546000600060006000604060606000600053604001536103e8f1327f6f776e65720000000000000000000000000000000000000000000000000000005761011663000000e46000396101166000f20060006000547f72656769737465720000000000000000000000000000000000000000000000006000602002350e0f630000006d596000600160200235560e0f630000006c59600032560e0f0f6300000057596000325657600260200235600160200235576001602002353257007f64657265676973746572000000000000000000000000000000000000000000006000602002350e0f63000000b95960016020023532560e0f63000000b959600032576000600160200235577f6b696c6c000000000000000000000000000000000000000000000000000000006000602002350e0f630000011559327f6f776e6572000000000000000000000000000000000000000000000000000000560e0f63000001155932ff00'; var dnsRegCode = '0x60006000546000600053602001546000600053604001546020604060206020600073661005d2720d855f1d9976f88bb10c1a3398c77f6103e8f17f7265676973746572000000000000000000000000000000000000000000000000600053606001600060200201547f446e735265670000000000000000000000000000000000000000000000000000600053606001600160200201546000600060006000604060606000600053604001536103e8f1327f6f776e65720000000000000000000000000000000000000000000000000000005761011663000000e46000396101166000f20060006000547f72656769737465720000000000000000000000000000000000000000000000006000602002350e0f630000006d596000600160200235560e0f630000006c59600032560e0f0f6300000057596000325657600260200235600160200235576001602002353257007f64657265676973746572000000000000000000000000000000000000000000006000602002350e0f63000000b95960016020023532560e0f63000000b959600032576000600160200235577f6b696c6c000000000000000000000000000000000000000000000000000000006000602002350e0f630000011559327f6f776e6572000000000000000000000000000000000000000000000000000000560e0f63000001155932ff00';
@ -73,240 +47,6 @@ env.note('DnsReg at address ' + dnsReg)
env.note('Register DnsReg...') env.note('Register DnsReg...')
eth.transact({ 'to': config, 'data': ['4', dnsReg] }); eth.transact({ 'to': config, 'data': ['4', dnsReg] });
*/
var coinRegCode = eth.lll("
{
(regname 'CoinReg)
(returnlll {
(def 'name $0)
(def 'denom $32)
(def 'address (caller))
(when (|| (& 0xffffffffffffffffffffffffff name) @@name) (stop))
(set 'n (+ @@0 1))
[[0]] @n
[[@n]] name
[[name]] address
[[(sha3 name)]] denom
})
}
");
var coinReg;
env.note('Create CoinReg...')
eth.transact({ 'code': coinRegCode }, function(a) { coinReg = a; });
env.note('Register CoinReg...')
eth.transact({ 'to': config, 'data': ['1', coinReg] });
var gavCoinCode = eth.lll("
{
[[ (caller) ]] 0x1000000
[[ 0x69 ]] (caller)
[[ 0x42 ]] (number)
(regname 'GavCoin)
(regcoin 'GAV 1000)
(returnlll {
(when (&& (= $0 'kill) (= (caller) @@0x69)) (suicide (caller)))
(when (= $0 'balance) (return @@$32))
(when (= $0 'approved) (return @@ (sha3pair (if (= (calldatasize) 64) (caller) $64) $32)) )
(when (= $0 'approve) {
[[(sha3pair (caller) $32)]] $32
(stop)
})
(when (= $0 'send) {
(set 'fromVar (if (= (calldatasize) 96)
(caller)
{
(when (! @@ (sha3pair (origin) (caller))) (return 0))
(origin)
}
))
(def 'to $32)
(def 'value $64)
(def 'from (get 'fromVar))
(set 'fromBal @@from)
(when (< @fromBal value) (return 0))
[[ from ]]: (- @fromBal value)
[[ to ]]: (+ @@to value)
(return 1)
})
(set 'n @@0x42)
(when (&& (|| (= $0 'mine) (! (calldatasize))) (> (number) @n)) {
(set 'b (- (number) @n))
[[(coinbase)]] (+ @@(coinbase) (* 1000 @b))
[[(caller)]] (+ @@(caller) (* 1000 @b))
[[0x42]] (number)
(return @b)
})
(return @@ $0)
})
}
");
var gavCoin;
env.note('Create GavCoin...')
eth.transact({ 'code': gavCoinCode }, function(a) { gavCoin = a; });
env.note('Register GavCoin...')
eth.transact({ 'to': config, 'data': ['2', gavCoin] });
var exchangeCode = eth.lll("
{
(regname 'Exchange)
(def 'min (a b) (if (< a b) a b))
(def 'head (_list) @@ _list)
(def 'next (_item) @@ _item)
(def 'inc (itemref) [itemref]: (next @itemref))
(def 'rateof (_item) @@ (+ _item 1))
(def 'idof (_item) @@ (+ _item 2))
(def 'wantof (_item) @@ (+ _item 3))
(def 'newitem (rate who want list) {
(set 'pos (sha3trip rate who list))
[[ (+ @pos 1) ]] rate
[[ (+ @pos 2) ]] who
[[ (+ @pos 3) ]] want
@pos
})
(def 'stitchitem (parent pos) {
[[ pos ]] @@ parent
[[ parent ]] pos
})
(def 'addwant (_item amount) [[ (+ _item 3) ]] (+ @@ (+ _item 3) amount))
(def 'deductwant (_item amount) [[ (+ _item 3) ]] (- @@ (+ _item 3) amount))
(def 'xfer (contract to amount)
(if contract {
[0] 'send
[32] to
[64] amount
(msg allgas contract 0 0 96)
}
(send to amount)
)
)
(def 'fpdiv (a b) (/ (+ (/ b 2) (* a (exp 2 128))) b))
(def 'fpmul (a b) (/ (* a b) (exp 2 128)) )
(returnlll {
(when (= $0 'new) {
(set 'offer $32)
(set 'xoffer (if @offer $64 (callvalue)))
(set 'want $96)
(set 'xwant $128)
(set 'rate (fpdiv @xoffer @xwant))
(set 'irate (fpdiv @xwant @xoffer))
(unless (&& @rate @irate @xoffer @xwant) (stop))
(when @offer {
(set 'arg1 'send)
(set 'arg2 (address))
(set 'arg3 @xoffer)
(set 'arg4 (caller))
(unless (msg allgas @offer 0 arg1 128) (stop))
})
(set 'list (sha3pair @offer @want))
(set 'ilist (sha3pair @want @offer))
(set 'last @ilist)
(set 'item @@ @last)
(for {} (&& @item (>= (rateof @item) @irate)) {} {
(set 'offerA (min @xoffer (wantof @item)))
(set 'wantA (fpmul @offerA (rateof @item)))
(set 'xoffer (- @xoffer @offerA))
(set 'xwant (- @xwant @wantA))
(deductwant @item @offerA)
(xfer @offer (idof @item) @offerA)
(xfer @want (caller) @wantA)
(unless @xoffer (stop))
(set 'item @@ @item)
[[ @last ]] @item
})
(set 'last @list)
(set 'item @@ @last)
(set 'newpos (newitem @rate (caller) @xwant @list))
(for {} (&& @item (!= @item @newpos) (>= (rateof @item) @rate)) { (set 'last @item) (inc item) } {})
(if (= @item @newpos)
(addwant @item @wantx)
(stitchitem @last @newpos)
)
(stop)
})
(when (= $0 'delete) {
(set 'offer $32)
(set 'want $64)
(set 'rate $96)
(set 'list (sha3pair @offer @want))
(set 'last @list)
(set 'item @@ @last)
(for {} (&& @item (!= (idof @item) (caller)) (!= (rateof @item) @rate)) { (set 'last @item) (inc item) } {})
(when @item {
(set 'xoffer (fpmul (wantof @item) (rateof @item)))
[[ @last ]] @@ @item
(xfer @offer (caller) @xoffer)
})
(stop)
})
(when (= $0 'price) {
(set 'offer $32)
(set 'want $96)
(set 'item (head (sha3pair @offer @want)))
(return (if @item (rateof @list) 0))
})
})
}
");
var exchange;
env.note('Create Exchange...')
eth.transact({ 'code': exchangeCode }, function(a) { exchange = a; });
env.note('Register Exchange...')
eth.transact({ 'to': config, 'data': ['3', exchange] });
env.note('Register my name...')
eth.transact({ 'to': nameReg, 'data': [ web3.fromAscii('register'), web3.fromAscii('Gav') ] });
env.note('Dole out ETH to other address...')
eth.transact({ 'value': '100000000000000000000', 'to': eth.accounts[1] });
env.note('Register my other name...')
eth.transact({ 'from': eth.keys[1], 'to': nameReg, 'data': [ web3.fromAscii('register'), web3.fromAscii("Gav Would") ] });
env.note('Approve Exchange...')
eth.transact({ 'to': gavCoin, 'data': [ web3.fromAscii('approve'), exchange ] });
env.note('Approve Exchange on other address...')
eth.transact({ 'from': eth.keys[1], 'to': gavCoin, 'data': [ web3.fromAscii('approve'), exchange ] });
env.note('Make offer 5000GAV/5ETH...')
eth.transact({ 'to': exchange, 'data': [web3.fromAscii('new'), gavCoin, '5000', '0', '5000000000000000000'] });
env.note('Register gav.eth...')
eth.transact({ 'to': dnsReg, 'data': [web3.fromAscii('register'), web3.fromAscii('gav'), web3.fromAscii('opensecrecy.com')] });
env.note('All done.')
// env.load('/home/gav/Eth/cpp-ethereum/stdserv.js') // env.load('/home/gav/Eth/cpp-ethereum/stdserv.js')

51
test/TestHelperCrypto.h

@ -1,51 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file TestHelperCrypto.h
* @author Alex Leverington <nessence@gmail.com>
* @date 2014
*/
#pragma once
#include <libdevcrypto/CryptoPP.h>
using namespace std;
using namespace CryptoPP;
void SavePrivateKey(const PrivateKey& key, const string& file = "ecies.private.key")
{
FileSink sink(file.c_str());
key.Save(sink);
}
void SavePublicKey(const PublicKey& key, const string& file = "ecies.public.key")
{
FileSink sink(file.c_str());
key.Save(sink);
}
void LoadPrivateKey(PrivateKey& key, const string& file = "ecies.private.key")
{
FileSource source(file.c_str(), true);
key.Load(source);
}
void LoadPublicKey(PublicKey& key, const string& file = "ecies.public.key")
{
FileSource source(file.c_str(), true);
key.Load(source);
}

277
test/crypto.cpp

@ -27,9 +27,9 @@
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libethereum/Transaction.h> #include <libethereum/Transaction.h>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <libdevcrypto/EC.h> #include <libdevcrypto/SHA3.h>
#include <libdevcrypto/SHA3MAC.h> #include <libdevcrypto/ECDHE.h>
#include "TestHelperCrypto.h" #include <libdevcrypto/CryptoPP.h>
using namespace std; using namespace std;
using namespace dev; using namespace dev;
@ -38,9 +38,24 @@ using namespace CryptoPP;
BOOST_AUTO_TEST_SUITE(devcrypto) BOOST_AUTO_TEST_SUITE(devcrypto)
static Secp256k1 s_secp256k1;
static CryptoPP::AutoSeededRandomPool s_rng;
static CryptoPP::OID s_curveOID(CryptoPP::ASN1::secp256k1());
static CryptoPP::DL_GroupParameters_EC<CryptoPP::ECP> s_params(s_curveOID);
static CryptoPP::DL_GroupParameters_EC<CryptoPP::ECP>::EllipticCurve s_curve(s_params.GetCurve());
BOOST_AUTO_TEST_CASE(verify_secert)
{
h256 empty;
KeyPair kNot(empty);
BOOST_REQUIRE(!kNot.address());
KeyPair k(sha3(empty));
BOOST_REQUIRE(k.address());
}
BOOST_AUTO_TEST_CASE(common_encrypt_decrypt) BOOST_AUTO_TEST_CASE(common_encrypt_decrypt)
{ {
string message("Now is the time for all good persons to come to the aide of humanity."); string message("Now is the time for all good persons to come to the aid of humanity.");
bytes m = asBytes(message); bytes m = asBytes(message);
bytesConstRef bcr(&m); bytesConstRef bcr(&m);
@ -56,103 +71,50 @@ BOOST_AUTO_TEST_CASE(common_encrypt_decrypt)
BOOST_REQUIRE(plain == asBytes(message)); BOOST_REQUIRE(plain == asBytes(message));
} }
BOOST_AUTO_TEST_CASE(cryptopp_vs_secp256k1)
{
ECIES<ECP>::Decryptor d(pp::PRNG, pp::secp256k1Curve);
ECIES<ECP>::Encryptor e(d.GetKey());
Secret s;
pp::exportPrivateKey(d.GetKey(), s);
Public p;
pp::exportPublicKey(e.GetKey(), p);
BOOST_REQUIRE(dev::toAddress(s) == right160(dev::sha3(p.ref())));
Secret previous = s;
for (auto i = 0; i < 2; i++)
{
ECIES<ECP>::Decryptor d(pp::PRNG, pp::secp256k1Curve);
ECIES<ECP>::Encryptor e(d.GetKey());
Secret s;
pp::exportPrivateKey(d.GetKey(), s);
BOOST_REQUIRE(s != previous);
Public p;
pp::exportPublicKey(e.GetKey(), p);
h160 secp256k1Addr = dev::toAddress(s);
h160 cryptoppAddr = right160(dev::sha3(p.ref()));
if (secp256k1Addr != cryptoppAddr)
{
BOOST_REQUIRE(secp256k1Addr == cryptoppAddr);
break;
}
}
}
BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_secp256k1libport) BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_secp256k1libport)
{ {
// cryptopp implementation of secp256k1lib sign_compact w/recid parameter and recovery of public key from signature secp256k1_start();
// base secret // base secret
Secret secret(sha3("privacy")); Secret secret(sha3("privacy"));
// we get ec params from signer // we get ec params from signer
const CryptoPP::DL_GroupParameters_EC<CryptoPP::ECP> params = pp::secp256k1Params;
ECDSA<ECP, SHA3_256>::Signer signer; ECDSA<ECP, SHA3_256>::Signer signer;
// e := sha3(msg) // e := sha3(msg)
bytes e(fromHex("0x01")); bytes e(fromHex("0x01"));
e.resize(32); e.resize(32);
int tests = 2; // Oct 29: successful @ 1500 int tests = 2;
while (sha3(&e, &e), secret = sha3(secret.asBytes()), tests--) while (sha3(&e, &e), secret = sha3(secret.asBytes()), tests--)
{ {
KeyPair key(secret); KeyPair key(secret);
Public pkey = key.pub(); Public pkey = key.pub();
pp::initializeDLScheme(secret, signer); signer.AccessKey().Initialize(s_params, secretToExponent(secret));
h256 he(sha3(e)); h256 he(sha3(e));
Integer heInt(he.asBytes().data(), 32); Integer heInt(he.asBytes().data(), 32);
h256 k(crypto::kdf(secret, he)); h256 k(crypto::kdf(secret, he));
Integer kInt(k.asBytes().data(), 32); Integer kInt(k.asBytes().data(), 32);
kInt %= params.GetSubgroupOrder()-1; kInt %= s_params.GetSubgroupOrder()-1;
ECP::Point rp = params.ExponentiateBase(kInt); ECP::Point rp = s_params.ExponentiateBase(kInt);
Integer const& q = params.GetGroupOrder(); Integer const& q = s_params.GetGroupOrder();
Integer r = params.ConvertElementToInteger(rp); Integer r = s_params.ConvertElementToInteger(rp);
int recid = ((r >= q) ? 2 : 0) | (rp.y.IsOdd() ? 1 : 0);
Integer kInv = kInt.InverseMod(q); Integer kInv = kInt.InverseMod(q);
Integer s = (kInv * (Integer(secret.asBytes().data(), 32)*r + heInt)) % q; Integer s = (kInv * (Integer(secret.asBytes().data(), 32)*r + heInt)) % q;
BOOST_REQUIRE(!!r && !!s); BOOST_REQUIRE(!!r && !!s);
/*
// For future reference:
// According to maths, this codepath can't be reached, however, it's in secp256k1.
// Commenting this out diverges from codebase implementation.
// To be removed after upstream PR and proof are evaulated.
if (s > params.GetSubgroupOrder())
{
// note: this rarely happens
s = params.GetGroupOrder() - s;
if (recid)
recid ^= 1;
}
*/
Signature sig; Signature sig;
sig[64] = rp.y.IsOdd() ? 1 : 0;
r.Encode(sig.data(), 32); r.Encode(sig.data(), 32);
s.Encode(sig.data() + 32, 32); s.Encode(sig.data() + 32, 32);
sig[64] = recid;
Public p = dev::recover(sig, he); Public p = dev::recover(sig, he);
BOOST_REQUIRE(p == pkey); BOOST_REQUIRE(p == pkey);
// verify w/cryptopp // verify w/cryptopp
BOOST_REQUIRE(crypto::verify(pkey, sig, bytesConstRef(&e))); BOOST_REQUIRE(s_secp256k1.verify(pkey, sig, bytesConstRef(&e)));
// verify with secp256k1lib // verify with secp256k1lib
byte encpub[65] = {0x04}; byte encpub[65] = {0x04};
@ -166,16 +128,18 @@ BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_secp256k1libport)
BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1)
{ {
secp256k1_start();
// cryptopp integer encoding // cryptopp integer encoding
Integer nHex("f2ee15ea639b73fa3db9b34a245bdfa015c260c598b211bf05a1ecc4b3e3b4f2H"); Integer nHex("f2ee15ea639b73fa3db9b34a245bdfa015c260c598b211bf05a1ecc4b3e3b4f2H");
Integer nB(fromHex("f2ee15ea639b73fa3db9b34a245bdfa015c260c598b211bf05a1ecc4b3e3b4f2").data(), 32); Integer nB(fromHex("f2ee15ea639b73fa3db9b34a245bdfa015c260c598b211bf05a1ecc4b3e3b4f2").data(), 32);
BOOST_REQUIRE(nHex == nB); BOOST_REQUIRE(nHex == nB);
bytes sbytes(fromHex("0x01")); bytes sbytes(fromHex("0xFFFF"));
Secret secret(sha3(sbytes)); // 5fe7f977e71dba2ea1a68e21057beebb9be2ac30c6410aa38d4f3fbe41dcffd2 Secret secret(sha3(sbytes));
KeyPair key(secret); KeyPair key(secret);
bytes m(fromHex("0x01")); bytes m(1, 0xff);
int tests = 2; int tests = 2;
while (m[0]++, tests--) while (m[0]++, tests--)
{ {
@ -183,45 +147,45 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1)
Integer hInt(hm.asBytes().data(), 32); Integer hInt(hm.asBytes().data(), 32);
h256 k(hm ^ key.sec()); h256 k(hm ^ key.sec());
Integer kInt(k.asBytes().data(), 32); Integer kInt(k.asBytes().data(), 32);
// raw sign w/cryptopp (doesn't pass through cryptopp hash filter) // raw sign w/cryptopp (doesn't pass through cryptopp hash filter)
ECDSA<ECP, SHA3_256>::Signer signer; ECDSA<ECP, SHA3_256>::Signer signer;
pp::initializeDLScheme(key.sec(), signer); signer.AccessKey().Initialize(s_params, secretToExponent(key.sec()));
Integer r, s; Integer r, s;
signer.RawSign(kInt, hInt, r, s); signer.RawSign(kInt, hInt, r, s);
// verify cryptopp raw-signature w/cryptopp // verify cryptopp raw-signature w/cryptopp
ECDSA<ECP, SHA3_256>::Verifier verifier; ECDSA<ECP, SHA3_256>::Verifier verifier;
pp::initializeDLScheme(key.pub(), verifier); verifier.AccessKey().Initialize(s_params, publicToPoint(key.pub()));
Signature sigppraw; Signature sigppraw;
r.Encode(sigppraw.data(), 32); r.Encode(sigppraw.data(), 32);
s.Encode(sigppraw.data() + 32, 32); s.Encode(sigppraw.data() + 32, 32);
BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), sigppraw.data(), 64)); BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), sigppraw.data(), 64));
BOOST_REQUIRE(crypto::verify(key.pub(), sigppraw, bytesConstRef(&m))); // BOOST_REQUIRE(crypto::verify(key.pub(), sigppraw, bytesConstRef(&m)));
BOOST_REQUIRE(dev::verify(key.pub(), sigppraw, hm)); BOOST_REQUIRE(dev::verify(key.pub(), sigppraw, hm));
// sign with cryptopp, verify, recover w/sec256lib // sign with cryptopp, verify, recover w/sec256lib
Signature seclibsig(dev::sign(key.sec(), hm)); Signature seclibsig(dev::sign(key.sec(), hm));
BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), seclibsig.data(), 64)); BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), seclibsig.data(), 64));
BOOST_REQUIRE(crypto::verify(key.pub(), seclibsig, bytesConstRef(&m))); // BOOST_REQUIRE(crypto::verify(key.pub(), seclibsig, bytesConstRef(&m)));
BOOST_REQUIRE(dev::verify(key.pub(), seclibsig, hm)); BOOST_REQUIRE(dev::verify(key.pub(), seclibsig, hm));
BOOST_REQUIRE(dev::recover(seclibsig, hm) == key.pub()); BOOST_REQUIRE(dev::recover(seclibsig, hm) == key.pub());
// sign with cryptopp (w/hash filter?), verify with cryptopp // sign with cryptopp (w/hash filter?), verify with cryptopp
bytes sigppb(signer.MaxSignatureLength()); bytes sigppb(signer.MaxSignatureLength());
size_t ssz = signer.SignMessage(pp::PRNG, m.data(), m.size(), sigppb.data()); size_t ssz = signer.SignMessage(s_rng, m.data(), m.size(), sigppb.data());
Signature sigpp; Signature sigpp;
memcpy(sigpp.data(), sigppb.data(), 64); memcpy(sigpp.data(), sigppb.data(), 64);
BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), sigppb.data(), ssz)); BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), sigppb.data(), ssz));
BOOST_REQUIRE(crypto::verify(key.pub(), sigpp, bytesConstRef(&m))); // BOOST_REQUIRE(crypto::verify(key.pub(), sigpp, bytesConstRef(&m)));
BOOST_REQUIRE(dev::verify(key.pub(), sigpp, hm)); BOOST_REQUIRE(dev::verify(key.pub(), sigpp, hm));
// sign with cryptopp and stringsource hash filter // sign with cryptopp and stringsource hash filter
string sigstr; string sigstr;
StringSource ssrc(asString(m), true, new SignerFilter(pp::PRNG, signer, new StringSink(sigstr))); StringSource ssrc(asString(m), true, new SignerFilter(s_rng, signer, new StringSink(sigstr)));
FixedHash<sizeof(Signature)> retsig((byte const*)sigstr.data(), Signature::ConstructFromPointer); FixedHash<sizeof(Signature)> retsig((byte const*)sigstr.data(), Signature::ConstructFromPointer);
BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), retsig.data(), 64)); BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), retsig.data(), 64));
BOOST_REQUIRE(crypto::verify(key.pub(), retsig, bytesConstRef(&m))); // BOOST_REQUIRE(crypto::verify(key.pub(), retsig, bytesConstRef(&m)));
BOOST_REQUIRE(dev::verify(key.pub(), retsig, hm)); BOOST_REQUIRE(dev::verify(key.pub(), retsig, hm));
/// verification w/sec256lib /// verification w/sec256lib
@ -247,92 +211,102 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1)
} }
} }
BOOST_AUTO_TEST_CASE(cryptopp_public_export_import)
{
ECIES<ECP>::Decryptor d(pp::PRNG, pp::secp256k1Curve);
ECIES<ECP>::Encryptor e(d.GetKey());
Secret s;
pp::exportPrivateKey(d.GetKey(), s);
Public p;
pp::exportPublicKey(e.GetKey(), p);
Address addr = right160(dev::sha3(p.ref()));
BOOST_REQUIRE(toAddress(s) == addr);
KeyPair l(s);
BOOST_REQUIRE(l.address() == addr);
}
BOOST_AUTO_TEST_CASE(ecies_eckeypair) BOOST_AUTO_TEST_CASE(ecies_eckeypair)
{ {
KeyPair k = KeyPair::create(); KeyPair k = KeyPair::create();
string message("Now is the time for all good persons to come to the aide of humanity."); string message("Now is the time for all good persons to come to the aid of humanity.");
string original = message; string original = message;
bytes b = asBytes(message); bytes b = asBytes(message);
encrypt(k.pub(), b); s_secp256k1.encrypt(k.pub(), b);
BOOST_REQUIRE(b != asBytes(original)); BOOST_REQUIRE(b != asBytes(original));
decrypt(k.sec(), b); s_secp256k1.decrypt(k.sec(), b);
BOOST_REQUIRE(b == asBytes(original)); BOOST_REQUIRE(b == asBytes(original));
} }
BOOST_AUTO_TEST_CASE(ecdhe_aes128_ctr_sha3mac) BOOST_AUTO_TEST_CASE(ecdh)
{ {
// New connections require new ECDH keypairs cnote << "Testing ecdh...";
// Every new connection requires a new EC keypair
// Every new trust requires a new EC keypair ECDH<ECP>::Domain dhLocal(s_curveOID);
// All connections should share seed for PRF (or PRNG) for nonces SecByteBlock privLocal(dhLocal.PrivateKeyLength());
SecByteBlock pubLocal(dhLocal.PublicKeyLength());
dhLocal.GenerateKeyPair(s_rng, privLocal, pubLocal);
ECDH<ECP>::Domain dhRemote(s_curveOID);
SecByteBlock privRemote(dhRemote.PrivateKeyLength());
SecByteBlock pubRemote(dhRemote.PublicKeyLength());
dhRemote.GenerateKeyPair(s_rng, privRemote, pubRemote);
assert(dhLocal.AgreedValueLength() == dhRemote.AgreedValueLength());
// local: send public to remote; remote: send public to local
// Local
SecByteBlock sharedLocal(dhLocal.AgreedValueLength());
assert(dhLocal.Agree(sharedLocal, privLocal, pubRemote));
// Remote
SecByteBlock sharedRemote(dhRemote.AgreedValueLength());
assert(dhRemote.Agree(sharedRemote, privRemote, pubLocal));
// Test
Integer ssLocal, ssRemote;
ssLocal.Decode(sharedLocal.BytePtr(), sharedLocal.SizeInBytes());
ssRemote.Decode(sharedRemote.BytePtr(), sharedRemote.SizeInBytes());
assert(ssLocal != 0);
assert(ssLocal == ssRemote);
// Now use our keys
KeyPair a = KeyPair::create();
byte puba[65] = {0x04};
memcpy(&puba[1], a.pub().data(), 64);
KeyPair b = KeyPair::create();
byte pubb[65] = {0x04};
memcpy(&pubb[1], b.pub().data(), 64);
ECDH<ECP>::Domain dhA(s_curveOID);
Secret shared;
BOOST_REQUIRE(dhA.Agree(shared.data(), a.sec().data(), pubb));
BOOST_REQUIRE(shared);
} }
BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) BOOST_AUTO_TEST_CASE(ecdhe)
{ {
cnote << "Testing cryptopp_ecies_message..."; cnote << "Testing ecdhe...";
string const message("Now is the time for all good persons to come to the aide of humanity.");
ECIES<ECP>::Decryptor localDecryptor(pp::PRNG, pp::secp256k1Curve);
SavePrivateKey(localDecryptor.GetPrivateKey());
ECIES<ECP>::Encryptor localEncryptor(localDecryptor); ECDHE a, b;
SavePublicKey(localEncryptor.GetPublicKey()); BOOST_CHECK_NE(a.pubkey(), b.pubkey());
ECIES<ECP>::Decryptor futureDecryptor;
LoadPrivateKey(futureDecryptor.AccessPrivateKey());
futureDecryptor.GetPrivateKey().ThrowIfInvalid(pp::PRNG, 3);
ECIES<ECP>::Encryptor futureEncryptor; ECDHE local;
LoadPublicKey(futureEncryptor.AccessPublicKey()); ECDHE remote;
futureEncryptor.GetPublicKey().ThrowIfInvalid(pp::PRNG, 3);
// encrypt/decrypt with local
string cipherLocal;
StringSource ss1 (message, true, new PK_EncryptorFilter(pp::PRNG, localEncryptor, new StringSink(cipherLocal) ) );
string plainLocal;
StringSource ss2 (cipherLocal, true, new PK_DecryptorFilter(pp::PRNG, localDecryptor, new StringSink(plainLocal) ) );
// encrypt/decrypt with future
string cipherFuture;
StringSource ss3 (message, true, new PK_EncryptorFilter(pp::PRNG, futureEncryptor, new StringSink(cipherFuture) ) );
string plainFuture;
StringSource ss4 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG, futureDecryptor, new StringSink(plainFuture) ) );
// decrypt local w/future // local tx pubkey -> remote
string plainFutureFromLocal; Secret sremote;
StringSource ss5 (cipherLocal, true, new PK_DecryptorFilter(pp::PRNG, futureDecryptor, new StringSink(plainFutureFromLocal) ) ); remote.agree(local.pubkey(), sremote);
// decrypt future w/local // remote tx pbukey -> local
string plainLocalFromFuture; Secret slocal;
StringSource ss6 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG, localDecryptor, new StringSink(plainLocalFromFuture) ) ); local.agree(remote.pubkey(), slocal);
BOOST_REQUIRE(sremote);
BOOST_REQUIRE(slocal);
BOOST_REQUIRE_EQUAL(sremote, slocal);
}
BOOST_AUTO_TEST_CASE(ecdhe_aes128_ctr_sha3mac)
{
// New connections require new ECDH keypairs
// Every new connection requires a new EC keypair
// Every new trust requires a new EC keypair
// All connections should share seed for PRF (or PRNG) for nonces
BOOST_REQUIRE(plainLocal == message);
BOOST_REQUIRE(plainFuture == plainLocal);
BOOST_REQUIRE(plainFutureFromLocal == plainLocal);
BOOST_REQUIRE(plainLocalFromFuture == plainLocal);
} }
BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr)
@ -346,21 +320,28 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr)
rng.GenerateBlock(key, key.size()); rng.GenerateBlock(key, key.size());
// cryptopp uses IV as nonce/counter which is same as using nonce w/0 ctr // cryptopp uses IV as nonce/counter which is same as using nonce w/0 ctr
byte ctr[AES::BLOCKSIZE]; FixedHash<AES::BLOCKSIZE> ctr;
rng.GenerateBlock(ctr, sizeof(ctr)); rng.GenerateBlock(ctr.data(), sizeof(ctr));
// used for decrypt
FixedHash<AES::BLOCKSIZE> ctrcopy(ctr);
string text = "Now is the time for all good persons to come to the aide of humanity."; string text = "Now is the time for all good persons to come to the aid of humanity.";
// c++11 ftw
unsigned char const* in = (unsigned char*)&text[0]; unsigned char const* in = (unsigned char*)&text[0];
unsigned char* out = (unsigned char*)&text[0]; unsigned char* out = (unsigned char*)&text[0];
string original = text; string original = text;
string doublespeak = text + text;
string cipherCopy; string cipherCopy;
try try
{ {
CTR_Mode<AES>::Encryption e; CTR_Mode<AES>::Encryption e;
e.SetKeyWithIV(key, key.size(), ctr); e.SetKeyWithIV(key, key.size(), ctr.data());
// 68 % 255 should be difference of counter
e.ProcessData(out, in, text.size()); e.ProcessData(out, in, text.size());
ctr = h128(u128(ctr) + text.size() % 16);
BOOST_REQUIRE(text != original); BOOST_REQUIRE(text != original);
cipherCopy = text; cipherCopy = text;
} }
@ -372,7 +353,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr)
try try
{ {
CTR_Mode< AES >::Decryption d; CTR_Mode< AES >::Decryption d;
d.SetKeyWithIV(key, key.size(), ctr); d.SetKeyWithIV(key, key.size(), ctrcopy.data());
d.ProcessData(out, in, text.size()); d.ProcessData(out, in, text.size());
BOOST_REQUIRE(text == original); BOOST_REQUIRE(text == original);
} }
@ -390,7 +371,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr)
out = (unsigned char*)&cipherCopy[0]; out = (unsigned char*)&cipherCopy[0];
CTR_Mode<AES>::Encryption e; CTR_Mode<AES>::Encryption e;
e.SetKeyWithIV(key, key.size(), ctr); e.SetKeyWithIV(key, key.size(), ctrcopy.data());
e.ProcessData(out, in, text.size()); e.ProcessData(out, in, text.size());
// yep, ctr mode. // yep, ctr mode.

6
windows/LibEthereum.vcxproj

@ -68,14 +68,14 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile> </ClCompile>
<ClCompile Include="..\libdevcore\_libdevcore.cpp" /> <ClCompile Include="..\libdevcore\_libdevcore.cpp" />
<ClCompile Include="..\libdevcrypto\AES.cpp" />
<ClCompile Include="..\libdevcrypto\Common.cpp" /> <ClCompile Include="..\libdevcrypto\Common.cpp" />
<ClCompile Include="..\libdevcrypto\CryptoPP.cpp" /> <ClCompile Include="..\libdevcrypto\CryptoPP.cpp" />
<ClCompile Include="..\libdevcrypto\EC.cpp" /> <ClCompile Include="..\libdevcrypto\ECDHE.cpp" />
<ClCompile Include="..\libdevcrypto\FileSystem.cpp" /> <ClCompile Include="..\libdevcrypto\FileSystem.cpp" />
<ClCompile Include="..\libdevcrypto\MemoryDB.cpp" /> <ClCompile Include="..\libdevcrypto\MemoryDB.cpp" />
<ClCompile Include="..\libdevcrypto\OverlayDB.cpp" /> <ClCompile Include="..\libdevcrypto\OverlayDB.cpp" />
<ClCompile Include="..\libdevcrypto\SHA3.cpp" /> <ClCompile Include="..\libdevcrypto\SHA3.cpp" />
<ClCompile Include="..\libdevcrypto\SHA3MAC.cpp" />
<ClCompile Include="..\libdevcrypto\TrieCommon.cpp" /> <ClCompile Include="..\libdevcrypto\TrieCommon.cpp" />
<ClCompile Include="..\libdevcrypto\TrieDB.cpp" /> <ClCompile Include="..\libdevcrypto\TrieDB.cpp" />
<ClCompile Include="..\libethcore\BlockInfo.cpp"> <ClCompile Include="..\libethcore\BlockInfo.cpp">
@ -574,4 +574,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>
</Project> </Project>

6
windows/LibEthereum.vcxproj.filters

@ -435,10 +435,10 @@
<ClInclude Include="..\libethereum\Account.h"> <ClInclude Include="..\libethereum\Account.h">
<Filter>libethereum</Filter> <Filter>libethereum</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\libevmcore\Assembly.h"> <ClInclude Include="..\libevmcore\Exceptions.h">
<Filter>libevmcore</Filter> <Filter>libevmcore</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\libevmcore\Exceptions.h"> <ClInclude Include="..\libevmcore\Assembly.h">
<Filter>libevmcore</Filter> <Filter>libevmcore</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\libevm\VMFace.h"> <ClInclude Include="..\libevm\VMFace.h">
@ -480,4 +480,4 @@
<UniqueIdentifier>{d838fece-fc20-42f6-bff5-97c236159b80}</UniqueIdentifier> <UniqueIdentifier>{d838fece-fc20-42f6-bff5-97c236159b80}</UniqueIdentifier>
</Filter> </Filter>
</ItemGroup> </ItemGroup>
</Project> </Project>

Loading…
Cancel
Save