From b0f4ca133967bb7a7c9610d83b96ee136e9c09b7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 4 Jan 2014 21:37:34 +0000 Subject: [PATCH] crypto prototyping. --- libethereum/Common.h | 53 +++++++++++++++++++++++++--------- libethereum/RLP.h | 15 ++++++---- libethereum/VirtualMachine.cpp | 23 +++++---------- libethereum/VirtualMachine.h | 7 +++-- test/CMakeLists.txt | 2 ++ test/main.cpp | 48 ++++++++++++++++++++++++++++++ 6 files changed, 110 insertions(+), 38 deletions(-) diff --git a/libethereum/Common.h b/libethereum/Common.h index 140b4b2d5..baaaddd65 100644 --- a/libethereum/Common.h +++ b/libethereum/Common.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "vector_ref.h" @@ -31,7 +32,7 @@ template inline std::string asHex(_T const& _data, int _w = 2) { std::ostringstream ret; for (auto i: _data) - ret << std::hex << std::setfill('0') << std::setw(_w) << (int)i; + ret << std::hex << std::setfill('0') << std::setw(_w) << (int)(typename std::make_unsigned::type)i; return ret.str(); } @@ -48,6 +49,32 @@ template void pushFront(_T& _t, _U _e) _t[0] = _e; } +class BadHexCharacter: public std::exception {}; + +inline int fromHex(char _i) +{ + if (_i >= '0' && _i <= '9') + return _i - '0'; + if (_i >= 'a' && _i <= 'f') + return _i - 'a' + 10; + if (_i >= 'A' && _i <= 'F') + return _i - 'A' + 10; + throw BadHexCharacter(); +} + +inline bytes fromUserHex(std::string const& _s) +{ + assert(_s.size() % 2 == 0); + if (_s.size() < 2) + return bytes(); + uint s = (_s[0] == '0' && _s[1] == 'x') ? 2 : 0; + std::vector ret; + ret.reserve((_s.size() - s) / 2); + for (uint i = s; i < _s.size(); i += 2) + ret.push_back(fromHex(_s[i]) * 16 + fromHex(_s[i + 1])); + return ret; +} + inline bytes toHex(std::string const& _s) { std::vector ret; @@ -60,25 +87,25 @@ inline bytes toHex(std::string const& _s) return ret; } -template -inline std::string toBigEndianString(_T _val, uint _s) +template +inline void toBigEndian(_T _val, _Out& o_out) { - std::string ret; - ret.resize(_s); - for (uint i = 0; i < _s; ++i, _val >>= 8) - ret[_s - 1 - i] = (char)(uint8_t)_val; - return ret; + auto s = o_out.size(); + for (uint i = 0; i < s; ++i, _val >>= 8) + o_out[s - 1 - i] = (typename _Out::value_type)(uint8_t)_val; } -inline std::string toBigEndianString(u256 _val) { return toBigEndianString(_val, 32); } -inline std::string toBigEndianString(u160 _val) { return toBigEndianString(_val, 20); } +inline std::string toBigEndianString(u256 _val) { std::string ret(32, '\0'); toBigEndian(_val, ret); return ret; } +inline std::string toBigEndianString(u160 _val) { std::string ret(20, '\0'); toBigEndian(_val, ret); return ret; } template inline std::string toCompactBigEndianString(_T _val) { - int i; - for (i = 0; _val; ++i, _val >>= 8) {} - return toBigEndianString(_val, i); + int i = 0; + for (_T v = _val; v; ++i, v >>= 8) {} + std::string ret(i, '\0'); + toBigEndian(_val, ret); + return ret; } template uint commonPrefix(_T const& _t, _U const& _u) diff --git a/libethereum/RLP.h b/libethereum/RLP.h index 4271f2a7e..d51c25294 100644 --- a/libethereum/RLP.h +++ b/libethereum/RLP.h @@ -119,6 +119,8 @@ public: m_lastItem = m_lastItem.cropped(0, RLP(m_lastItem).actualSize()); m_remaining -= std::min(m_remaining, m_lastItem.size()); } + else + m_lastItem.retarget(m_lastItem.next().data(), 0); return *this; } iterator operator++(int) { auto ret = *this; operator++(); return ret; } @@ -128,16 +130,17 @@ public: private: iterator() {} - iterator(bytesConstRef _payload, bool _begin) + iterator(RLP const& _parent, bool _begin) { if (_begin) { - m_lastItem = _payload.cropped(RLP(_payload).actualSize()); - m_remaining = _payload.size() - m_lastItem.size(); + auto pl = _parent.payload(); + m_lastItem = pl.cropped(0, RLP(pl).actualSize()); + m_remaining = pl.size() - m_lastItem.size(); } else { - m_lastItem = _payload.cropped(m_lastItem.size()); + m_lastItem = _parent.data().cropped(_parent.data().size()); m_remaining = 0; } } @@ -146,8 +149,8 @@ public: }; friend class iterator; - iterator begin() const { return iterator(payload(), true); } - iterator end() const { return iterator(payload(), false); } + iterator begin() const { return iterator(*this, true); } + iterator end() const { return iterator(*this, false); } explicit operator std::string() const { return toString(); } explicit operator RLPs() const { return toList(); } diff --git a/libethereum/VirtualMachine.cpp b/libethereum/VirtualMachine.cpp index 6f3bfaa5a..a94291cc4 100644 --- a/libethereum/VirtualMachine.cpp +++ b/libethereum/VirtualMachine.cpp @@ -15,30 +15,21 @@ u256 const State::c_newContractFee = 0; Transaction::Transaction(bytes const& _rlpData) { RLP rlp(_rlpData); - nonce = rlp[0].toFatIntFromString(); + nonce = rlp[0].toFatIntStrict(); receiveAddress = as160(rlp[1].toFatIntFromString()); value = rlp[2].toFatIntStrict(); fee = rlp[3].toFatIntStrict(); data.reserve(rlp[4].itemCountStrict()); for (auto const& i: rlp[4]) data.push_back(i.toFatIntStrict()); - vrs = Signature{ rlp[5].toFatIntFromString(), rlp[6].toFatIntFromString(), rlp[7].toFatIntFromString() }; + vrs = Signature{ rlp[5].toFatIntStrict(), rlp[6].toFatIntStrict(), rlp[7].toFatIntStrict() }; } -bytes Transaction::rlp() const +void Transaction::fillStream(RLPStream& _s, bool _sig) const { - RLPStream rlp; - rlp << RLPList(8); - if (nonce) - rlp << nonce; - else - rlp << ""; - if (receiveAddress) - rlp << toCompactBigEndianString(receiveAddress); - else - rlp << ""; - rlp << value << fee << data << toCompactBigEndianString(vrs.v) << toCompactBigEndianString(vrs.r) << toCompactBigEndianString(vrs.s); - return rlp.out(); + _s << RLPList(8) << nonce << toCompactBigEndianString(receiveAddress) << value << fee << data; + if (_sig) + _s << toCompactBigEndianString(vrs.v) << toCompactBigEndianString(vrs.r) << toCompactBigEndianString(vrs.s); } bool State::execute(Transaction const& _t, u160 _sender) @@ -447,7 +438,7 @@ void State::execute(u160 _myAddress, u160 _txSender, u256 _txValue, u256 _txFee, } t.nonce = transactionsFrom(_myAddress); - execute(t); + execute(t, _myAddress); break; } diff --git a/libethereum/VirtualMachine.h b/libethereum/VirtualMachine.h index e2fc9a85f..61c81adcf 100644 --- a/libethereum/VirtualMachine.h +++ b/libethereum/VirtualMachine.h @@ -207,8 +207,10 @@ struct Transaction u256s data; Signature vrs; - bytes rlp() const; - u256 sha256() const { return eth::sha256(rlp()); } + void fillStream(RLPStream& _s, bool _sig = true) const; + bytes rlp(bool _sig = true) const { RLPStream s; fillStream(s, _sig); return s.out(); } + std::string rlpString(bool _sig = true) const { RLPStream s; fillStream(s, _sig); return s.str(); } + u256 sha256(bool _sig = true) const { RLPStream s; fillStream(s, _sig); return eth::sha256(s.out()); } }; class State @@ -220,7 +222,6 @@ public: bool execute(bytes const& _rlp) { try { Transaction t(_rlp); u160 sender = t.vrs.address(bytesConstRef(const_cast(&_rlp))); return execute(t, sender); } catch (...) { return false; } } // remove const_cast once vector_ref can handle const vector* properly. private: - bool execute(Transaction const& _t); bool execute(Transaction const& _t, u160 _sender); bool isNormalAddress(u160 _address) const { auto it = m_current.find(_address); return it != m_current.end() && it->second.type() == AddressType::Normal; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e383ba2db..2bafaea35 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -8,4 +8,6 @@ link_directories(../../secp256k1) add_executable(testeth ${SRC_LIST}) +target_link_libraries(testeth secp256k1) target_link_libraries(testeth ethereum) +target_link_libraries(testeth gmp) diff --git a/test/main.cpp b/test/main.cpp index e78f3ce03..006814368 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -20,7 +20,55 @@ std::string randomWord() int main() { + secp256k1_start(); + bytes pubkey(65); + int pubkeylen = 65; + { + cout << "SEC: " << asHex(sha256("123", false)) << endl; + int ret = secp256k1_ecdsa_pubkey_create(pubkey.data(), &pubkeylen, (byte const*)sha256("123", false).data(), 1); + pubkey.resize(pubkeylen); + cout << "PUB: " << ret << " " << pubkeylen << " " << asHex(pubkey) << endl; + } + + bytes tx = fromUserHex("88005401010101010101010101010101010101010101011f0de0b6b3a76400001ce8d4a5100080181c373130a009ba1f10285d4e659568bfcfec85067855c5a3c150100815dad4ef98fd37cf0593828c89db94bd6c64e210a32ef8956eaa81ea9307194996a3b879441f5d"); + cout << "TX: " << RLP(tx) << endl; + + Transaction t(tx); + std::string sig64 = toBigEndianString(t.vrs.r) + toBigEndianString(t.vrs.s); + cout << "SIG: " << sig64.size() << " " << asHex(sig64) << " " << t.vrs.v << endl; + + auto msg = t.rlp(false); + cout << "TX w/o SIG: " << RLP(msg) << endl; + cout << "RLP(TX w/o SIG): " << asHex(t.rlpString(false)) << endl; + std::string hmsg = sha256(t.rlpString(false), false); + cout << "SHA256(RLP(TX w/o SIG)): 0x" << asHex(hmsg) << endl; + + { + bytes sig(64); + u256 nonce = 0; + int v = 0; + int ret = secp256k1_ecdsa_sign_compact((byte const*)hmsg.data(), hmsg.size(), sig.data(), (byte const*)sha256("123", false).data(), (byte const*)&nonce, &v); + cout << "MYSIG: " << dec << ret << " " << sig.size() << " " << asHex(sig) << " " << v << endl; + + ret = secp256k1_ecdsa_recover_compact((byte const*)hmsg.data(), hmsg.size(), (byte const*)sig.data(), pubkey.data(), &pubkeylen, 1, (int)t.vrs.v); + pubkey.resize(pubkeylen); + cout << "MYREC: " << dec << ret << " " << pubkeylen << " " << asHex(pubkey) << endl; + } + + { + pubkey.resize(65); + int ret = secp256k1_ecdsa_recover_compact((byte const*)hmsg.data(), hmsg.size(), (byte const*)sig64.data(), pubkey.data(), &pubkeylen, 1, (int)t.vrs.v); + pubkey.resize(pubkeylen); + cout << "REC: " << dec << ret << " " << pubkeylen << " " << asHex(pubkey) << endl; + cout << hex << sha256(pubkey) << endl; + + pubkey.resize(65); + ret = secp256k1_ecdsa_recover_compact((byte const*)hmsg.data(), hmsg.size(), (byte const*)sig64.data(), pubkey.data(), &pubkeylen, 0, (int)t.vrs.v); + pubkey.resize(pubkeylen); + cout << "REC+: " << dec << ret << " " << pubkeylen << " " << asHex(pubkey) << endl; + cout << hex << sha256(pubkey) << endl; + } { Trie t;