From 318bf043edfc981a1aaa33ade7f1895cd108e69d Mon Sep 17 00:00:00 2001 From: Vitalik Buterin Date: Fri, 19 May 2017 00:15:23 -0400 Subject: [PATCH] Added a few utility files --- forwarder.py | 39 +++++++++++++++++++ mk_sendmany.py | 23 +++++++++++ sendmany_tester.py | 14 +++++++ .../py_pairing/py_pairing/optimized_curve.py | 6 +-- .../py_pairing/optimized_pairing.py | 16 ++++++-- 5 files changed, 91 insertions(+), 7 deletions(-) create mode 100644 forwarder.py create mode 100644 mk_sendmany.py create mode 100644 sendmany_tester.py diff --git a/forwarder.py b/forwarder.py new file mode 100644 index 0000000..9014f89 --- /dev/null +++ b/forwarder.py @@ -0,0 +1,39 @@ +from ethereum import utils + +def mk_forwarder(address): + code = b'\x36\x60\x00\x60\x00\x37' # CALLDATACOPY 0 0 (CALLDATASIZE) + code += b'\x61\x20\x00\x60\x00\x36\x60\x00' # 8192 0 CALLDATASIZE 0 + code += b'\x73' + utils.normalize_address(address) + b'\x5a' # address gas + code += b'\xf4' # delegatecall + code += b'\x61\x20\x00\x60\x00\xf3' # 8192 0 RETURN + return code + +def mk_wrapper(code): + lencodepush = b'\x60' + utils.encode_int(len(code)) # length of code + returner = lencodepush + b'\x60\x0c\x60\x00' # start from 12 in code, 0 in memory + returner += b'\x39' # CODECOPY + returner += lencodepush + b'\x60\x00' + b'\xf3' # return code + assert len(returner) == 12 + return returner + code + +kode = """ +moose: num +def increment_moose(i: num) -> num: + self.moose += i + return self.moose +""" + +def test(): + from ethereum.tools import tester2 + c = tester2.Chain() + x = c.contract(kode, language='viper') + fwdcode = mk_forwarder(x.address) + initcode = mk_wrapper(fwdcode) + y = c.contract(initcode, language='evm') + assert c.head_state.get_code(y) == fwdcode + z = tester2.ABIContract(c, x.translator, y) + assert z.increment_moose(3) == 3 + assert z.increment_moose(5) == 8 + +if __name__ == '__main__': + test() diff --git a/mk_sendmany.py b/mk_sendmany.py new file mode 100644 index 0000000..1a3cb71 --- /dev/null +++ b/mk_sendmany.py @@ -0,0 +1,23 @@ +from ethereum import utils + +def mk_multisend_code(payments): # expects a dictionary, {address: wei} + kode = b'' + for address, wei in payments.items(): + kode += b'\x60\x00\x60\x00\x60\x00\x60\x00' # 0 0 0 0 + encoded_wei = utils.encode_int(wei) or b'\x00' + kode += utils.ascii_chr(0x5f + len(encoded_wei)) + encoded_wei # value + kode += b'\x73' + utils.normalize_address(address) # to + kode += b'\x60\x00\xf1\x50' # 0 CALL POP + kode += b'\x33\xff' # CALLER SELFDESTRUCT + return kode + +def get_multisend_gas(payments): + o = 26002 # 21000 + 2 (CALLER) + 5000 (SELFDESTRUCT) + for address, wei in payments.items(): + encoded_wei = utils.encode_int(wei) or b'\x00' + # 20 bytes in txdata for address = 1360 + # bytes in txdata for wei = 68 * n + # gas for pushes and pops = 3 * 7 + 2 = 23 + # CALL = 9700 + 25000 (possible if new account) + o += 1360 + 68 * len(encoded_wei) + 23 + 34700 + return o diff --git a/sendmany_tester.py b/sendmany_tester.py new file mode 100644 index 0000000..011574b --- /dev/null +++ b/sendmany_tester.py @@ -0,0 +1,14 @@ +from mk_sendmany import mk_multisend_code, get_multisend_gas +from ethereum.tools import tester2 +from ethereum import utils + +# from ethereum.slogging import get_logger, configure_logging +# logger = get_logger() +# configure_logging(':trace') + +c = tester2.Chain() +args = {utils.int_to_addr(10000 + i ** 3): i ** 3 for i in range(1, 101)} +c.tx(to=b'', value=sum(args.values()), data=mk_multisend_code(args), startgas=get_multisend_gas(args), gasprice=20 * 10**9) +for addr, value in args.items(): + assert c.head_state.get_balance(addr) == value +print("Test successful") diff --git a/zksnark/py_pairing/py_pairing/optimized_curve.py b/zksnark/py_pairing/py_pairing/optimized_curve.py index 6859821..1e78d68 100644 --- a/zksnark/py_pairing/py_pairing/optimized_curve.py +++ b/zksnark/py_pairing/py_pairing/optimized_curve.py @@ -24,7 +24,7 @@ G2 = (FQ2([108570469990230571359445707622328294813707563595785180869905199932856 # Check that a point is on the curve defined by y**2 == x**3 + b def is_on_curve(pt, b): - if pt is None: + if pt[-1] == pt[-1].__class__.zero(): return True x, y, z = pt return y**2 * z - x**3 == b * z**3 @@ -49,7 +49,7 @@ def double(pt): def add(p1, p2): one, zero = p1[0].__class__.one(), p1[0].__class__.zero() if p1[2] == zero or p2[2] == zero: - return p1 if zero else p2 + return p1 if p2[2] == zero else p2 x1, y1, z1 = p1 x2, y2, z2 = p2 U1 = y2 * z1 @@ -75,7 +75,7 @@ def add(p1, p2): # Elliptic curve point multiplication def multiply(pt, n): if n == 0: - return None + return (pt[0].__class__.one(), pt[0].__class__.one(), pt[0].__class__.zero()) elif n == 1: return pt elif not n % 2: diff --git a/zksnark/py_pairing/py_pairing/optimized_pairing.py b/zksnark/py_pairing/py_pairing/optimized_pairing.py index 2b9656b..f05dba4 100644 --- a/zksnark/py_pairing/py_pairing/optimized_pairing.py +++ b/zksnark/py_pairing/py_pairing/optimized_pairing.py @@ -64,7 +64,7 @@ assert linefunc(one, one, two)[0] != FQ(0) assert linefunc(one, one, negtwo)[0] == FQ(0) # Main miller loop -def miller_loop(Q, P): +def miller_loop(Q, P, final_exponentiate=True): if Q is None or P is None: return FQ12.one() R = Q @@ -97,10 +97,18 @@ def miller_loop(Q, P): _n2, _d2 = linefunc(R, nQ2, P) f = f_num * _n1 * _n2 / (f_den * _d1 * _d2) # R = add(R, nQ2) This line is in many specifications but it technically does nothing - return f ** ((field_modulus ** 12 - 1) // curve_order) + if final_exponentiate: + return f ** ((field_modulus ** 12 - 1) // curve_order) + else: + return f # Pairing computation -def pairing(Q, P): +def pairing(Q, P, final_exponentiate=True): assert is_on_curve(Q, b2) assert is_on_curve(P, b) - return miller_loop(twist(Q), cast_point_to_fq12(P)) + if P[-1] == P[-1].__class__.zero() or Q[-1] == Q[-1].__class__.zero(): + return FQ12.one() + return miller_loop(twist(Q), cast_point_to_fq12(P), final_exponentiate=final_exponentiate) + +def final_exponentiate(p): + return p ** ((field_modulus ** 12 - 1) // curve_order)