Skip to content
This repository has been archived by the owner on Oct 28, 2021. It is now read-only.

Commit

Permalink
RIP-EMD160 implementation for the VM.
Browse files Browse the repository at this point in the history
Additional VM instructions.
  • Loading branch information
gavofyork committed Jan 3, 2014
1 parent a96d072 commit 6f10722
Show file tree
Hide file tree
Showing 6 changed files with 567 additions and 11 deletions.
53 changes: 53 additions & 0 deletions libethereum/Common.cpp
@@ -1,2 +1,55 @@
#include "Common.h"
#include "rmd160.h"
using namespace std;
using namespace eth;

/* collect four bytes into one word: */
#define BYTES_TO_DWORD(strptr) \
(((uint32_t) *((strptr)+3) << 24) | \
((uint32_t) *((strptr)+2) << 16) | \
((uint32_t) *((strptr)+1) << 8) | \
((uint32_t) *(strptr)))

u256 eth::ripemd160(fConstBytes _message)
/*
* returns RMD(message)
* message should be a string terminated by '\0'
*/
{
static const uint RMDsize = 160;
uint32_t MDbuf[RMDsize/32]; /* contains (A, B, C, D(, E)) */
static byte hashcode[RMDsize/8]; /* for final hash-value */
uint32_t X[16]; /* current 16-word chunk */
unsigned int i; /* counter */
uint32_t length; /* length in bytes of message */
uint32_t nbytes; /* # of bytes not yet processed */

/* initialize */
MDinit(MDbuf);
length = _message.size();
auto message = _message.data();

/* process message in 16-word chunks */
for (nbytes=length; nbytes > 63; nbytes-=64) {
for (i=0; i<16; i++) {
X[i] = BYTES_TO_DWORD(message);
message += 4;
}
compress(MDbuf, X);
} /* length mod 64 bytes left */

/* finish: */
MDfinish(MDbuf, message, length, 0);

for (i=0; i<RMDsize/8; i+=4) {
hashcode[i] = MDbuf[i>>2]; /* implicit cast to byte */
hashcode[i+1] = (MDbuf[i>>2] >> 8); /* extracts the 8 least */
hashcode[i+2] = (MDbuf[i>>2] >> 16); /* significant bits. */
hashcode[i+3] = (MDbuf[i>>2] >> 24);
}

u256 ret = 0;
for (i = 0; i < RMDsize / 8; ++i)
ret = (ret << 8) | hashcode[i];
return ret;
}
2 changes: 2 additions & 0 deletions libethereum/Common.h
Expand Up @@ -74,4 +74,6 @@ template <class _T, class _U> uint commonPrefix(_T const& _t, _U const& _u)
return s;
}

u256 ripemd160(fConstBytes _message);

}
91 changes: 88 additions & 3 deletions libethereum/VirtualMachine.cpp
@@ -1,3 +1,4 @@
#include "sha256.h"
#include "VirtualMachine.h"
using namespace std;
using namespace eth;
Expand Down Expand Up @@ -34,56 +35,140 @@ void VirtualMachine::go()
require(2);
m_stack[m_stack.size() - 2] += m_stack.back();
m_stack.pop_back();
break;
case Instruction::MUL:
//pops two items and pushes S[-1] * S[-2] mod 2^256.
require(2);
m_stack[m_stack.size() - 2] *= m_stack.back();
m_stack.pop_back();
break;
case Instruction::SUB:
require(2);
m_stack[m_stack.size() - 2] = m_stack.back() - m_stack[m_stack.size() - 2];
m_stack.pop_back();
break;
case Instruction::DIV:
require(2);
m_stack[m_stack.size() - 2] = m_stack.back() / m_stack[m_stack.size() - 2];
m_stack.pop_back();
break;
case Instruction::SDIV:
require(2);
(s256&)m_stack[m_stack.size() - 2] = (s256&)m_stack.back() / (s256&)m_stack[m_stack.size() - 2];
m_stack.pop_back();
break;
case Instruction::MOD:
require(2);
m_stack[m_stack.size() - 2] = m_stack.back() % m_stack[m_stack.size() - 2];
m_stack.pop_back();
break;
case Instruction::SMOD:
require(2);
(s256&)m_stack[m_stack.size() - 2] = (s256&)m_stack.back() % (s256&)m_stack[m_stack.size() - 2];
m_stack.pop_back();
break;
case Instruction::EXP:
{
// TODO: better implementation?
require(2);
// (s256&)m_stack[m_stack.size() - 2] = pow(m_stack.back(), m_stack[m_stack.size() - 2]);
// m_stack.pop_back();
auto n = m_stack.back();
auto x = m_stack[m_stack.size() - 2];
m_stack.pop_back();
for (u256 i = 0; i < x; ++i)
n *= n;
m_stack.back() = n;
break;
}
case Instruction::NEG:
require(1);
m_stack.back() = ~(m_stack.back() - 1);
break;
case Instruction::LT:
require(2);
m_stack[m_stack.size() - 2] = m_stack.back() < m_stack[m_stack.size() - 2] ? 1 : 0;
m_stack.pop_back();
break;
case Instruction::LE:
require(2);
m_stack[m_stack.size() - 2] = m_stack.back() <= m_stack[m_stack.size() - 2] ? 1 : 0;
m_stack.pop_back();
break;
case Instruction::GT:
require(2);
m_stack[m_stack.size() - 2] = m_stack.back() > m_stack[m_stack.size() - 2] ? 1 : 0;
m_stack.pop_back();
break;
case Instruction::GE:
require(2);
m_stack[m_stack.size() - 2] = m_stack.back() >= m_stack[m_stack.size() - 2] ? 1 : 0;
m_stack.pop_back();
break;
case Instruction::EQ:
require(2);
m_stack[m_stack.size() - 2] = m_stack.back() == m_stack[m_stack.size() - 2] ? 1 : 0;
m_stack.pop_back();
break;
case Instruction::NOT:
require(1);
m_stack.back() = m_stack.back() ? 0 : 1;
m_stack.pop_back();
break;
case Instruction::MYADDRESS:
case Instruction::MYCREATOR:
m_stack.push_back(m_myAddress);
break;
case Instruction::TXSENDER:
m_stack.push_back(m_txSender);
break;
case Instruction::TXVALUE:
m_stack.push_back(m_txValue);
break;
case Instruction::TXFEE:
m_stack.push_back(m_txFee);
break;
case Instruction::TXDATAN:
m_stack.push_back(m_txData.size());
break;
case Instruction::TXDATA:
require(1);
m_stack.back() = m_stack.back() < m_txData.size() ? m_txData[(uint)m_stack.back()] : 0;
break;
case Instruction::BLK_PREVHASH:
m_stack.push_back(m_previousBlock.hash);
break;
case Instruction::BLK_COINBASE:
m_stack.push_back(m_currentBlock.coinbase);
break;
case Instruction::BLK_TIMESTAMP:
m_stack.push_back(m_currentBlock.timestamp);
break;
case Instruction::BLK_NUMBER:
m_stack.push_back(m_currentBlock.number);
break;
case Instruction::BLK_DIFFICULTY:
m_stack.push_back(m_currentBlock.difficulty);
break;
case Instruction::SHA256:
case Instruction::RIPEMD160:
{
uint s = (uint)min(m_stack.back(), (u256)(m_stack.size() - 1) * 32);
bytes b(s);
uint i = 0;
for (; s; s = (s >= 32 ? s - 32 : 0), i += 32)
{
m_stack.pop_back();
u256 v = m_stack.back();
int sz = (int)min<u256>(32, s) - 1; // sz is one fewer than the number of bytes we're interested in.
v >>= ((31 - sz) * 8); // kill unused low-order bytes.
for (int j = 0; j <= sz; ++j, v >>= 8) // cycle through bytes, starting at low-order end.
b[i + sz - j] = (byte)(v & 0xff); // set each 32-byte (256-bit) chunk in reverse - (i.e. we want to put low-order last).
}
if (inst == Instruction::SHA256)
m_stack.back() = sha256(b);
else
m_stack.back() = ripemd160(&b);

break;
}
case Instruction::ECMUL:
case Instruction::ECADD:
case Instruction::ECSIGN:
Expand Down
35 changes: 27 additions & 8 deletions libethereum/VirtualMachine.h
Expand Up @@ -23,14 +23,13 @@ enum class Instruction: uint8_t
SMOD, ///< Rx Ry Rz - like MOD, but for signed values just like SDIV (using Python's convention with negative numbers)
EXP, ///< Rx Ry Rz - sets Rz <- Rx ^ Ry mod 2^256
NEG, ///< Rx Ry - sets Ry <- 2^256 - Rx
LT = 0x10, ///< Rx Ry Rz - sets Rz <- 1 if Rx < Ry else 0
LT, ///< Rx Ry Rz - sets Rz <- 1 if Rx < Ry else 0
LE, ///< Rx Ry Rz - sets Rz <- 1 if Rx <= Ry else 0
GT, ///< Rx Ry Rz - sets Rz <- 1 if Rx > Ry else 0
GE, ///< Rx Ry Rz - sets Rz <- 1 if Rx >= Ry else 0
EQ, ///< Rx Ry Rz - sets Rz <- 1 if Rx = Ry else 0
NOT, ///< Rx Ry - sets Ry <- 1 if Rx = 0 else 0
MYADDRESS = 0x20, ///< Rx - sets Rx to the contract's own address
MYCREATOR, ///< Rx - sets Rx to the contract's own address
MYADDRESS = 0x10, ///< Rx - sets Rx to the contract's own address
TXSENDER, ///< pushes the transaction sender
TXVALUE , ///< pushes the transaction value
TXFEE, ///< pushes the transaction fee
Expand All @@ -41,33 +40,42 @@ enum class Instruction: uint8_t
BLK_TIMESTAMP, ///< pushes the timestamp of the current block
BLK_NUMBER, ///< pushes the current block number
BLK_DIFFICULTY, ///< pushes the difficulty of the current block
SHA256 = 0x30, ///< sets Ry <- SHA256(Rx)
SHA256 = 0x20, ///< sets Ry <- SHA256(Rx)
RIPEMD160, ///< Rx Ry - sets Ry <- RIPEMD160(Rx)
ECMUL, ///< Rx Ry Rz Ra Rb - sets (Ra, Rb) = Rz * (Rx, Ry) in secp256k1, using (0,0) for the point at infinity
ECADD, ///< Rx Ry Rz Ra Rb Rc - sets (Rb, Rc) = (Rx, Ry) + (Ra, Rb)
ECSIGN, ///< Rx Ry Rz Ra Rb - sets(Rz, Ra, Rb)as the(r,s,prefix)values of an Electrum-style RFC6979 deterministic signature ofRxwith private keyRy`
ECRECOVER, ///< Rx Ry Rz Ra Rb Rc - sets(Rb, Rc)as the public key from the signature(Ry, Rz, Ra)of the message hashRx`
ECVALID, ///< Rx Ry Rz Ra Rb Rc - sets(Rb, Rc)as the public key from the signature(Ry, Rz, Ra)of the message hashRx`
PUSH = 0x40,
PUSH = 0x30,
POP,
DUP,
DUPN,
SWAP,
SWAPN,
LOAD,
STORE,
JMP = 0x50, ///< Rx - sets the index pointer to the value at Rx
JMP = 0x40, ///< Rx - sets the index pointer to the value at Rx
JMPI, ///< Rx Ry - if Rx != 0, sets the index pointer to Ry
IND, ///< pushes the index pointer.
EXTRO = 0x60, ///< Rx Ry Rz - looks at the contract at address Rx and its memory state Ry, and outputs the result to Rz
EXTRO = 0x50, ///< Rx Ry Rz - looks at the contract at address Rx and its memory state Ry, and outputs the result to Rz
BALANCE, ///< Rx - returns the ether balance of address Rx
MKTX = 0x70, ///< Rx Ry Rz Rw Rv - sends Ry ether to Rx plus Rz fee with Rw data items starting from memory index Rv (and then reading to (Rv + 1), (Rv + 2) etc). Note that if Rx = 0 then this creates a new contract.
MKTX = 0x60, ///< Rx Ry Rz Rw Rv - sends Ry ether to Rx plus Rz fee with Rw data items starting from memory index Rv (and then reading to (Rv + 1), (Rv + 2) etc). Note that if Rx = 0 then this creates a new contract.
SUICIDE = 0xff ///< Rx - destroys the contract and clears all memory, sending the entire balance plus the negative fee from clearing memory minus TXFEE to the address
};

class BadInstruction: public std::exception {};
class StackTooSmall: public std::exception { public: StackTooSmall(uint _req, uint _got): req(_req), got(_got) {} uint req; uint got; };

struct BlockInfo
{
u256 hash;
u256 coinbase;
u256 timestamp;
u256 number;
u256 difficulty;
};

class VirtualMachine
{
public:
Expand All @@ -91,6 +99,17 @@ class VirtualMachine
u256 m_extroFee;
u256 m_minerFee;
u256 m_voidFee;

u256 m_myAddress;
u256 m_txSender;
u256 m_txValue;
u256 m_txFee;
std::vector<u256> m_txData;

BlockInfo m_previousBlock;
BlockInfo m_currentBlock;


};

}
Expand Down

0 comments on commit 6f10722

Please sign in to comment.