diff --git a/impurity/check_for_impurity.se b/impurity/check_for_impurity.se new file mode 100644 index 0000000..e4ccae0 --- /dev/null +++ b/impurity/check_for_impurity.se @@ -0,0 +1,61 @@ +macro calldatachar($x): + div(calldataload($x), 2**248) + +# sum([2**x for x in [0x31, 0x32, 0x33, 0x3a, 0x3b, 0x3c, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x54, 0x55, 0xf0, 0xff]) +mask = 57897811465722876096115075801844696845150819816717215668290421542284681019392 + +data approved_addrs[] + +def submit(addr: address): + # Copy external contract code + extcode = string(~extcodesize(addr)) + ~extcodecopy(addr, extcode, 0, ~extcodesize(addr)) + ops = array(~extcodesize(addr)) + pushargs = array(~extcodesize(addr)) + # Loop through the code + with i = 0: + with op = 0: + while i < len(extcode): + with c = ~mod(~mload(extcode + i - 31), 256): + # Banned opcode + if ~and(2**c, mask): + ~invalid() + # PUSH + if 0x60 <= c and c <= 0x7f: + pushargs[op] = ~div(~mload(extcode + i + 1), 256 ** (0x7f - c)) + i += c - 0x5e + # Call, callcode, delegatecall + elif c == 0xf1 or c == 0xf2 or c == 0xf4: + # Pattern-match two ways of setting the gas parameter: + # + # 1. PUSH + # 2. sub(gas, PUSH) + if op >= 2 and ops[op - 1] >= 0x60 and ops[op - 1] <= 0x7f: + address_entry = op - 2 + elif op >= 4 and ops[op - 1] == 0x03 and ops[op - 2] == 0x5a and ops[op - 3] >= 0x60 and ops[op - 3] <= 0x7f: + address_entry = op - 4 + else: + ~invalid() + # Operation before the gas parameter must satisfy one of three conditions: + # + # 1. It is a PUSH of an already approved address + # 2. It is the address itself, through the ADDRESS opcode (ie. self-calling is permitted) + # 3. It is a PUSH1, ie. less than 256 (ie. a present or future precompile) + if self.approved_addrs[pushargs[address_entry]]: + success = 1 + elif ops[address_entry] == 0x30: + success = 1 + elif ops[address_entry] == 0x60: + success = 1 + if not success: + ~invalid() + i += 1 + else: + i += 1 + ops[op] = c + op += 1 + self.approved_addrs[addr] = 1 + return(1: bool) + +def check(addr: address): + return(self.approved_addrs[addr]:bool) diff --git a/impurity/impurity_tester.py b/impurity/impurity_tester.py new file mode 100644 index 0000000..e1db22b --- /dev/null +++ b/impurity/impurity_tester.py @@ -0,0 +1,122 @@ +from ethereum import tester as t +from ethereum import utils +from ethereum import transactions +import rlp +import serpent +s = t.state() +c = s.abi_contract('check_for_impurity.se') + +#from ethereum.slogging import LogRecorder, configure_logging, set_level +#config_string = ':info,eth.vm.log:trace,eth.vm.op:trace,eth.vm.stack:trace,eth.vm.exit:trace,eth.pb.msg:trace,eth.pb.tx:debug' +#configure_logging(config_string=config_string) + +test1 = s.abi_contract(""" + +data horse + +def foo(): + return self.horse + +""") + +try: + c.submit(test1.address) + success = True +except: + success = False +assert not success + +failedtest_addr = "0x"+utils.encode_hex(test1.address) + +test2 = s.abi_contract(""" + +def foo(): + return block.number + +""") + +try: + c.submit(test2.address) + success = True +except: + success = False +assert not success + +test3 = s.abi_contract(""" + +def foo(x): + return x * 2 +""") + +c.submit(test3.address) + + + +test4 = s.abi_contract(""" + +def modexp(b: uint256, e: uint256, m: uint256): + if e == 0: + return 1 + elif e == 1: + return b + elif e % 2 == 0: + return self.modexp(~mulmod(b, b, m), ~div(e, 2), m) + elif e % 2 == 1: + return ~mulmod(self.modexp(~mulmod(b, b, m), ~div(e, 2), m), b, m) + +""") + +c.submit(test4.address) +modexp_addr = "0x"+utils.encode_hex(test4.address) + +test5 = s.abi_contract(""" + +def modinv(b, m): + inpdata = [0xa7d4bbe6, b, m-2, m] + outdata = [0] + ~call(100000, %s, 0, inpdata + 28, 100, outdata, 32) + return outdata[0] + +""" % modexp_addr) + +c.submit(test5.address) + +test6 = s.abi_contract(""" +def phooey(h, v, r, s): + return ecrecover(h, v, r, s) +""") + +c.submit(test6.address) + +test7 = s.abi_contract(""" + +def modinv(b, m): + inpdata = [0xa7d4bbe6, b, m-2, m] + outdata = [0] + ~call(msg.gas - 10000, %s, 0, inpdata + 28, 100, outdata, 32) + return outdata[0] + +""" % failedtest_addr) + +try: + c.submit(test7.address) + success = True +except: + success = False +assert not success + +print('All tests passed') + +kode = serpent.compile('check_for_impurity.se') + +# Create transaction +t = transactions.Transaction(0, 30 * 10**9, 2999999, '', 0, kode) +t.startgas = t.intrinsic_gas_used + 50000 + 200 * len(kode) +t.v = 27 +t.r = 45 +t.s = 79 +print('Send %d wei to %s' % (t.startgas * t.gasprice, + '0x'+utils.encode_hex(t.sender))) + +print('Contract address: 0x'+utils.encode_hex(utils.mk_contract_address(t.sender, 0))) +print('Code: 0x'+utils.encode_hex(rlp.encode(t)))