From 3ec98d01813167cc8725a951bd384c629158af2b Mon Sep 17 00:00:00 2001 From: Vitalik Buterin Date: Wed, 31 May 2017 05:40:37 -0400 Subject: [PATCH] Updated ECC example --- examples/ecc/ecrecover.se | 6 +-- examples/ecc/jacobian_arith.se | 10 ++-- examples/ecc/modexp.se | 2 +- examples/ecc/ringsig.se | 4 +- examples/ecc/substitutes.py | 14 +++--- examples/ecc/test.py | 83 ++++++++++++++++------------------ 6 files changed, 56 insertions(+), 63 deletions(-) diff --git a/examples/ecc/ecrecover.se b/examples/ecc/ecrecover.se index ff9c980..fac091a 100644 --- a/examples/ecc/ecrecover.se +++ b/examples/ecc/ecrecover.se @@ -3,8 +3,8 @@ # that I created. It may possible to achieve a further 20-50% savings by applying # that version. -extern modint.type: [add:[int256,int256,int256,int256,int256,int256]:int256[], decompose:[int256[]]:int256[], double:[int256,int256,int256]:int256[], exp:[int256,int256,int256]:int256, mul:[int256,int256,int256,int256]:int256[], recover_y:[int256,int256]:int256] -extern modexp.se: [exp:[int256,int256,int256]:int256] +extern modint.type: [add:[uint256,uint256,uint256,uint256,uint256,uint256]:int256[], decompose:[int256[]]:int256[], double:[uint256,uint256,uint256]:int256[], exp:[uint256,uint256,uint256]:int256, mul:[uint256,uint256,uint256,uint256]:int256[], recover_y:[uint256,int256]:int256] +extern modexp.se: [exp:[uint256,uint256,uint256]:int256] data JACOBIAN_ARITH data EXP @@ -17,7 +17,7 @@ def init(): event PubkeyTripleLogEvent(x:uint256, y:uint256, z:uint256) -def ecrecover(h, v, r, s): +def ecrecover(h: uint256, v: uint256, r: uint256, s: uint256): h = mod(h, N) r = mod(r, P) s = mod(s, N) diff --git a/examples/ecc/jacobian_arith.se b/examples/ecc/jacobian_arith.se index bb96825..61e4160 100644 --- a/examples/ecc/jacobian_arith.se +++ b/examples/ecc/jacobian_arith.se @@ -1,6 +1,6 @@ inset('modint.type') -def double(m_ax, m_ay, m_az): +def double(m_ax: uint256, m_ay: uint256, m_az: uint256): if !m_ay: return([0, 0, 0]:arr) with P_______P = -4294968273: @@ -18,7 +18,7 @@ def double(m_ax, m_ay, m_az): ~mstore(~msize(), m_nz) return((~msize() - 96):arr) -def add(m_ax, m_ay, m_az, m_bx, m_by, m_bz): +def add(m_ax: uint256, m_ay: uint256, m_az: uint256, m_bx: uint256, m_by: uint256, m_bz:uint256): if !m_ay: return([m_bx, m_by, m_bz]:arr) if !m_by: @@ -48,7 +48,7 @@ def add(m_ax, m_ay, m_az, m_bx, m_by, m_bz): return((~msize() - 96):arr) -def mul(m_bx, m_by, m_bz, n): +def mul(m_bx: uint256, m_by: uint256, m_bz: uint256, n: uint256): n = mod(n, -432420386565659656852420866394968145599) if !m_bx * !m_by + !n: # Constant-gas version of !axn and !ayn or !n return([0, 0, 1]:arr) @@ -100,7 +100,7 @@ def mul(m_bx, m_by, m_bz, n): return(o:arr) -def recover_y(x, y_bit): +def recover_y(x: uint256, y_bit): N = -432420386565659656852420866394968145599 P = -4294968273 xcubed = mulmod(mulmod(x, x, P), x, P) @@ -109,7 +109,7 @@ def recover_y(x, y_bit): return(beta * y_is_positive + (P - beta) * (1 - y_is_positive)) -def exp(b, e, m): +def exp(b: uint256, e: uint256, m: uint256): with o = 1: with bit = 2 ^ 255: while gt(bit, 0): diff --git a/examples/ecc/modexp.se b/examples/ecc/modexp.se index 1086ae8..25e4d3e 100644 --- a/examples/ecc/modexp.se +++ b/examples/ecc/modexp.se @@ -1,4 +1,4 @@ -def exp(b, e, m): +def exp(b: uint256, e: uint256, m:uint256): with o = 1: with bit = 2 ^ 255: while gt(bit, 0): diff --git a/examples/ecc/ringsig.se b/examples/ecc/ringsig.se index 552184b..17c7daf 100644 --- a/examples/ecc/ringsig.se +++ b/examples/ecc/ringsig.se @@ -1,6 +1,6 @@ # TOTALLY NOT TESTED AND LIKELY BROKEN AT THIS POINT; AWAITING A TEST SUITE -extern modint.type: [add:[int256,int256,int256,int256,int256,int256]:int256[], decompose:[int256[]]:int256[], double:[int256,int256,int256]:int256[], exp:[int256,int256,int256]:int256, mul:[int256,int256,int256,int256]:int256[], recover_y:[int256,int256]:int256] +extern modint.type: [add:[uint256,uint256,uint256,uint256,uint256,uint256]:int256[], decompose:[int256[]]:int256[], double:[uint256,uint256,uint256]:int256[], exp:[uint256,uint256,uint256]:int256, mul:[uint256,uint256,uint256,uint256]:int256[], recover_y:[uint256,int256]:int256] Gx = 55066263022277343669578718895168534326250603453777594175500187360389116729240 Gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424 P = -4294968273 @@ -37,7 +37,7 @@ event PubkeyLogEvent(x:uint256, y:uint256) event PubkeyTripleLogEvent(x:uint256, y:uint256, z:uint256) -def hash_pubkey_to_pubkey(pub:arr): +def hash_pubkey_to_pubkey(pub:uint256[]): x = sha3(pub:arr) while 1: xcubed = mulmod(mulmod(x, x, P), x, P) diff --git a/examples/ecc/substitutes.py b/examples/ecc/substitutes.py index d2d0703..d468880 100644 --- a/examples/ecc/substitutes.py +++ b/examples/ecc/substitutes.py @@ -7,7 +7,7 @@ def signed(o): if not isinstance(o, (list, tuple)): return o - 2**256 if o >= 2**255 else o - return map(lambda x: x - 2**256 if x >= 2**255 else x, o) + return list(map(lambda x: x - 2**256 if x >= 2**255 else x, o)) def hamming_weight(n): @@ -40,7 +40,7 @@ def modexp_substitute(base, exp, mod): def ecrecover_substitute(z, v, r, s): P, A, B, N, Gx, Gy = b.P, b.A, b.B, b.N, b.Gx, b.Gy x = r - beta = pow(x*x*x+A*x+B, (P + 1) / 4, P) + beta = pow(x*x*x+A*x+B, (P + 1) // 4, P) y = beta if v % 2 ^ beta % 2 else (P - beta) Gz = b.jacobian_multiply((Gx, Gy, 1), (N - z) % N) XY = b.jacobian_multiply((x, y, 1), s) @@ -53,7 +53,7 @@ def recover_y(x, y_bit): N = 2**256-432420386565659656852420866394968145599 P = 2**256-4294968273 xcubed = x**3 % P - beta = pow((x**3 + 7) % P, (P + 1) / 4, P) + beta = pow((x**3 + 7) % P, (P + 1) // 4, P) y_is_positive = y_bit ^ (beta % 2) ^ 1 return(beta * y_is_positive + (P - beta) * (1 - y_is_positive)) @@ -76,15 +76,15 @@ def decompose(Q): return([ox, oy]) def hash_array(arr): - o = '' + o = b'' for x in arr: - if isinstance(x, (int, long)): + if isinstance(x, int): x = utils.zpad(utils.encode_int(x), 32) o += x return utils.big_endian_to_int(utils.sha3(o)) def hash_value(x): - if isinstance(x, (int, long)): + if isinstance(x, int): x = utils.zpad(utils.encode_int(x), 32) return utils.big_endian_to_int(utils.sha3(x)) @@ -140,7 +140,7 @@ def ringsig_sign_substitute(msghash, priv, pub_xs, pub_ys): return (e[0]["left"], s, I[0], I[1] % 2) def bit(bytez, i): - return (ord(bytez[i // 8]) / 2**(i % 8)) % 2 + return (ord(bytez[i // 8]) // 2**(i % 8)) % 2 def ringsig_verify_substitute(msghash, x0, s, Ix, Iy, pub_xs, pub_ys): # Number of pubkeys diff --git a/examples/ecc/test.py b/examples/ecc/test.py index 2ac2a55..f2ab9b6 100644 --- a/examples/ecc/test.py +++ b/examples/ecc/test.py @@ -2,7 +2,7 @@ import random import sys import math -from ethereum import tester as t +from ethereum.tools import tester as t from ethereum import utils import substitutes import time @@ -18,9 +18,8 @@ def neg_point(p): return [p[0], b.P - p[1], p[2]] -s = t.state() -s.block.gas_limit = 100000000 -t.gas_limit = 3000000 +s = t.Chain() +s.head_state.gas_limit = 10**9 tests = sys.argv[1:] @@ -28,68 +27,64 @@ def neg_point(p): t.set_logging_level(int((tests+[1])[tests.index('--log') + 1])) if '--modexp' in tests or not len(tests): - c = s.abi_contract('jacobian_arith.se') - print "Starting modexp tests" + c = s.contract('jacobian_arith.se', language='serpent') + print("Starting modexp tests") for i in range(0, len(vals) - 2, 3): o1 = substitutes.modexp_substitute(vals[i], vals[i+1], vals[i+2]) - o2 = c.exp(vals[i], vals[i+1], vals[i+2], profiling=1) - print "gas", o2["gas"], "time", o2["time"] - assert o1 == o2["output"], (o1, o2) + o2 = c.exp(vals[i], vals[i+1], vals[i+2]) + assert o1 == o2 if '--double' in tests or not len(tests): - print "Starting doubling tests" - c = s.abi_contract('jacobian_arith.se') + print("Starting doubling tests") + c = s.contract('jacobian_arith.se', language='serpent') for i in range(5): - print 'trying doubling test', vals[i] + print('trying doubling test', vals[i]) P = b.to_jacobian(b.privtopub(vals[i])) o1 = substitutes.jacobian_double_substitute(*list(P)) - o2 = c.double(*(list(P)), profiling=2) - print "gas", o2["gas"], "time", o2["time"], "ops", o2["ops"] - assert o1 == o2["output"], (o1, o2) + o2 = c.double(*(list(P))) + assert o1 == o2, (o1, o2) if '--add' in tests or not len(tests): - print "Starting addition tests" - c = s.abi_contract('jacobian_arith.se') + print("Starting addition tests") + c = s.contract('jacobian_arith.se', language='serpent') for i in range(5): - print 'trying addition test', vals[i * 2], vals[i * 2 + 1] + print('trying addition test', vals[i * 2], vals[i * 2 + 1]) P = b.to_jacobian(b.privtopub(vals[i * 2])) Q = b.to_jacobian(b.privtopub(vals[i * 2 + 1])) o1 = substitutes.jacobian_add_substitute(*(list(P) + list(Q))) - o2 = c.add(*(list(P) + list(Q)), profiling=2) - print "gas", o2["gas"], "time", o2["time"], "ops", o2["ops"] - assert o1 == o2["output"], (o1, o2) + o2 = c.add(*(list(P) + list(Q))) + assert o1 == o2 if '--mul' in tests or not len(tests): - print "Starting multiplication tests" - c = s.abi_contract('jacobian_arith.se') + print("Starting multiplication tests") + c = s.contract('jacobian_arith.se', language='serpent') for i in range(5): - print 'trying multiplication test', vals[i * 2], vals[i * 2 + 1] + print('trying multiplication test', vals[i * 2], vals[i * 2 + 1]) P = b.to_jacobian(b.privtopub(vals[i * 2])) q = vals[i * 2 + 1] o1 = substitutes.jacobian_mul_substitute(*(list(P) + [q])) a = time.time() - print list(P) + [q] - o2 = c.mul(*(list(P) + [q]), profiling=1) - print "gas", o2["gas"], "time", o2["time"] - assert o1 == o2["output"], (o1, o2) + print(list(P) + [q]) + o2 = c.mul(*(list(P) + [q])) + assert o1 == o2 if '--ecrecover' in tests or not len(tests): - c = s.abi_contract('ecrecover.se') - print "Starting ecrecover tests" + c = s.contract('ecrecover.se', language='serpent') + print("Starting ecrecover tests") for i in range(5): - print 'trying ecrecover_test', vals[i*2], vals[i*2+1] + print('trying ecrecover_test', vals[i*2], vals[i*2+1]) k = vals[i*2] h = vals[i*2+1] V, R, S = b.ecdsa_raw_sign(b.encode(h, 256, 32), k) aa = time.time() o1 = substitutes.ecrecover_substitute(h, V, R, S) - print 'Native execution time:', time.time() - aa + print('Native execution time:', time.time() - aa) a = time.time() o2 = c.ecrecover(h, V, R, S) - print 'time', time.time() - a, 'gas', s.block.get_receipts()[-1].gas_used - s.block.get_receipts()[-2].gas_used + print('time', time.time() - a, 'gas', s.head_state.receipts[-1].gas_used - s.head_state.receipts[-2].gas_used) assert o1 == o2, (o1, o2) # Explicit tests @@ -107,14 +102,14 @@ def neg_point(p): assert o1 == o2, (o1, o2) if '--ringsig' in tests or not len(tests): - print "Starting ringsig tests" - c = s.abi_contract('ringsig.se') + print("Starting ringsig tests") + c = s.contract('ringsig.se', language='serpent') for L in range(2, 6): privs = vals[:L] my_priv = vals[1] - pubs = map(b.privtopub, privs) + pubs = list(map(b.privtopub, privs)) for pub in pubs: - assert map(substitutes.signed, list(substitutes.hash_to_pubkey(list(pub)))) == \ + assert list(map(substitutes.signed, list(substitutes.hash_to_pubkey(list(pub))))) == \ c.hash_pubkey_to_pubkey(list(pub)) pub_xs = [x[0] for x in pubs] pub_ys = [] @@ -127,11 +122,9 @@ def neg_point(p): x0, s_vals, Ix, Iy = substitutes.ringsig_sign_substitute(msghash, my_priv, pub_xs, pub_ys) t1 = time.time() assert substitutes.ringsig_verify_substitute(msghash, x0, s_vals, Ix, Iy, pub_xs, pub_ys) - print 'Native execution time: ', time.time() - t1 - ogl = t.gas_limit - t.gas_limit = 10000000 - o = c.verify(msghash, x0, s_vals, Ix, Iy, pub_xs, pub_ys, profiling=1) - assert o["output"] - print 'number of pubkeys', L, 'gas', o["gas"], 'time', o["time"], \ - 'totalgas', s.block.get_receipts()[-1].gas_used - s.block.get_receipts()[-2].gas_used - t.gas_limit = ogl + print('Native execution time: ', time.time() - t1) + t2 = time.time() + o = c.verify(msghash, x0, s_vals, Ix, Iy, pub_xs, pub_ys, startgas=10**7) + assert o + print('number of pubkeys', L, \ + 'totalgas', s.head_state.receipts[-1].gas_used - s.head_state.receipts[-2].gas_used, 'EVM verification time:', time.time() - t2)