Browse Source

Signatures working.

cl-refactor
Gav Wood 11 years ago
parent
commit
07dd3b61e1
  1. 25
      libethereum/Common.h
  2. 24
      libethereum/VirtualMachine.cpp
  3. 12
      libethereum/VirtualMachine.h
  4. 12
      libethereum/sha256.cpp
  5. 11
      libethereum/sha256.h
  6. 65
      test/main.cpp

25
libethereum/Common.h

@ -1,6 +1,7 @@
#pragma once
#include <cassert>
#include <random>
#include <sstream>
#include <cstdint>
#include <type_traits>
@ -98,6 +99,9 @@ inline void toBigEndian(_T _val, _Out& o_out)
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; }
inline bytes toBigEndian(u256 _val) { bytes ret(32); toBigEndian(_val, ret); return ret; }
inline bytes toBigEndian(u160 _val) { bytes ret(20); toBigEndian(_val, ret); return ret; }
template <class _T>
inline std::string toCompactBigEndianString(_T _val)
{
@ -119,4 +123,25 @@ template <class _T, class _U> uint commonPrefix(_T const& _t, _U const& _u)
u256 ripemd160(bytesConstRef _message);
inline std::string randomWord()
{
static std::mt19937_64 s_eng(0);
std::string ret(std::uniform_int_distribution<int>(4, 10)(s_eng), ' ');
char const n[] = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
std::uniform_int_distribution<int> d(0, sizeof(n) - 2);
for (char& c: ret)
c = n[d(s_eng)];
return ret;
}
template <class _T> inline std::vector<_T>& operator+=(std::vector<_T>& _a, std::vector<_T> const& _b)
{
auto s = _a.size();
_a.resize(_a.size() + _b.size());
memcpy(_a.data() + s, _b.data(), _b.size() * sizeof(_T));
return _a;
}
template <class _T> inline std::vector<_T> operator+(std::vector<_T> const& _a, std::vector<_T> const& _b) { std::vector<_T> ret(_a); return ret += _b; }
}

24
libethereum/VirtualMachine.cpp

@ -12,6 +12,23 @@ u256 const State::c_extroFee = 0;
u256 const State::c_cryptoFee = 0;
u256 const State::c_newContractFee = 0;
u160 Transaction::sender() const
{
State::ensureCrypto();
bytes sig = toBigEndian(vrs.r) + toBigEndian(vrs.s);
assert(sig.size() == 64);
RLPStream rlp;
fillStream(rlp, false);
bytes msg = eth::sha256Bytes(rlp.out());
bytes pubkey(65);
int pubkeylen = 65;
if (!secp256k1_ecdsa_recover_compact(msg.data(), msg.size(), sig.data(), pubkey.data(), &pubkeylen, 0, (int)vrs.v - 27))
throw InvalidSignature();
return low160(eth::sha256(bytesConstRef(&pubkey).cropped(1)));
}
Transaction::Transaction(bytes const& _rlpData)
{
RLP rlp(_rlpData);
@ -27,11 +44,16 @@ Transaction::Transaction(bytes const& _rlpData)
void Transaction::fillStream(RLPStream& _s, bool _sig) const
{
_s << RLPList(8) << nonce << toCompactBigEndianString(receiveAddress) << value << fee << data;
_s << RLPList(_sig ? 8 : 5) << nonce << toCompactBigEndianString(receiveAddress) << value << fee << data;
if (_sig)
_s << toCompactBigEndianString(vrs.v) << toCompactBigEndianString(vrs.r) << toCompactBigEndianString(vrs.s);
}
void State::ensureCrypto()
{
secp256k1_start();
}
bool State::execute(Transaction const& _t, u160 _sender)
{
// Entry point for a contract-originated transaction.

12
libethereum/VirtualMachine.h

@ -70,6 +70,7 @@ class StackTooSmall: public std::exception { public: StackTooSmall(u256 _req, u2
class OperandOutOfRange: public std::exception { public: OperandOutOfRange(u256 _min, u256 _max, u256 _got): mn(_min), mx(_max), got(_got) {} u256 mn; u256 mx; u256 got; };
class ExecutionException: public std::exception {};
class NoSuchContract: public std::exception {};
class InvalidSignature: public std::exception {};
class InvalidTransactionFormat: public std::exception {};
class InvalidBlockFormat: public std::exception {};
class InvalidUnclesHash: public std::exception {};
@ -186,11 +187,6 @@ struct Signature
u256 v;
u256 r;
u256 s;
u160 address(bytesConstRef _tx) const
{
return as160(s);
}
};
@ -207,6 +203,8 @@ struct Transaction
u256s data;
Signature vrs;
u160 sender() const;
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(); }
@ -218,8 +216,10 @@ class State
public:
explicit State(u256 _minerAddress): m_minerAddress(_minerAddress) {}
static void ensureCrypto();
bool verify(bytes const& _block);
bool execute(bytes const& _rlp) { try { Transaction t(_rlp); u160 sender = t.vrs.address(bytesConstRef(const_cast<bytes*>(&_rlp))); return execute(t, sender); } catch (...) { return false; } } // remove const_cast once vector_ref can handle const vector* properly.
bool execute(bytes const& _rlp) { try { Transaction t(_rlp); return execute(t, t.sender()); } catch (...) { return false; } } // remove const_cast once vector_ref can handle const vector* properly.
private:
bool execute(Transaction const& _t, u160 _sender);

12
libethereum/sha256.cpp

@ -181,17 +181,13 @@ std::string eth::sha256(std::string const& _input, bool _hex)
return std::string(buf);
}
u256 eth::sha256(bytes const& _input)
bytes eth::sha256Bytes(bytesConstRef _input)
{
u256 ret = 0;
bytes ret(SHA256::DIGEST_SIZE);
SHA256 ctx = SHA256();
ctx.init();
ctx.update(_input.data(), _input.size());
uint8_t buf[SHA256::DIGEST_SIZE];
ctx.final(buf);
for (unsigned i = 0; i < 32; ++i)
ret = (ret << 8) | buf[i];
ctx.update((byte*)_input.data(), _input.size());
ctx.final(ret.data());
return ret;
}

11
libethereum/sha256.h

@ -25,9 +25,14 @@ protected:
uint32_t m_h[8];
};
std::string sha256(std::string const& input, bool _hex);
u256 sha256(bytes const& input);
u256 sha256(bytesConstRef input);
std::string sha256(std::string const& _input, bool _hex);
bytes sha256Bytes(bytesConstRef _input);
inline bytes sha256Bytes(std::string const& _input) { return sha256Bytes((std::string*)&_input); }
inline bytes sha256Bytes(bytes const& _input) { return sha256Bytes((bytes*)&_input); }
u256 sha256(bytesConstRef _input);
inline u256 sha256(bytes const& _input) { return sha256(bytesConstRef((bytes*)&_input)); }
#define SHA2_SHFR(x, n) (x >> n)
#define SHA2_ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))

65
test/main.cpp

@ -7,35 +7,15 @@
using namespace std;
using namespace eth;
std::string randomWord()
{
static std::mt19937_64 s_eng(0);
std::string ret(uniform_int_distribution<int>(4, 10)(s_eng), ' ');
char const n[] = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
uniform_int_distribution<int> d(0, sizeof(n) - 2);
for (char& c: ret)
c = n[d(s_eng)];
return ret;
}
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 << "SENDER: " << hex << t.sender() << endl;
bytes sig64 = toBigEndian(t.vrs.r) + toBigEndian(t.vrs.s);
cout << "SIG: " << sig64.size() << " " << asHex(sig64) << " " << t.vrs.v << endl;
auto msg = t.rlp(false);
@ -44,30 +24,45 @@ int main()
std::string hmsg = sha256(t.rlpString(false), false);
cout << "SHA256(RLP(TX w/o SIG)): 0x" << asHex(hmsg) << endl;
bytes privkey = sha256Bytes("123");
secp256k1_start();
{
bytes pubkey(65);
int pubkeylen = 65;
int ret = secp256k1_ecdsa_seckey_verify(privkey.data());
cout << "SEC: " << dec << ret << " " << asHex(privkey) << endl;
ret = secp256k1_ecdsa_pubkey_create(pubkey.data(), &pubkeylen, privkey.data(), 1);
pubkey.resize(pubkeylen);
int good = secp256k1_ecdsa_pubkey_verify(pubkey.data(), pubkey.size());
cout << "PUB: " << dec << ret << " " << pubkeylen << " " << asHex(pubkey) << (good ? " GOOD" : " BAD") << endl;
}
// Test roundtrip...
{
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);
int ret = secp256k1_ecdsa_sign_compact((byte const*)hmsg.data(), hmsg.size(), sig.data(), privkey.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);
bytes pubkey(65);
int pubkeylen = 65;
ret = secp256k1_ecdsa_recover_compact((byte const*)hmsg.data(), hmsg.size(), (byte const*)sig.data(), pubkey.data(), &pubkeylen, 0, 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);
bytes pubkey(65);
int pubkeylen = 65;
int ret = secp256k1_ecdsa_recover_compact((byte const*)hmsg.data(), hmsg.size(), (byte const*)sig64.data(), pubkey.data(), &pubkeylen, 0, (int)t.vrs.v - 27);
pubkey.resize(pubkeylen);
cout << "REC+: " << dec << ret << " " << pubkeylen << " " << asHex(pubkey) << endl;
cout << hex << sha256(pubkey) << endl;
cout << "RECPUB: " << dec << ret << " " << pubkeylen << " " << asHex(pubkey) << endl;
cout << "SENDER: " << hex << low160(eth::sha256(bytesConstRef(&pubkey).cropped(1))) << endl;
}
{

Loading…
Cancel
Save