From b7fca258771b2928deb80ea87c6498ea4e8e888b Mon Sep 17 00:00:00 2001 From: Jared Wasinger Date: Sat, 30 Jul 2022 15:56:30 -0400 Subject: [PATCH 01/12] wip --- evmmax_generator/generate.py | 64 ++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 evmmax_generator/generate.py diff --git a/evmmax_generator/generate.py b/evmmax_generator/generate.py new file mode 100644 index 0000000..a086cf4 --- /dev/null +++ b/evmmax_generator/generate.py @@ -0,0 +1,64 @@ + +MAX_LIMBS = 11 + +PUSH3_POP_ITER_COUNT = 0 +EVMMAX_ARITH_ITER_COUNT = 0 +raise Exception("TODO^") + +EVMMAX_ARITH_OPS = { + "ADDMODMAX": {}, + "SUBMODMAX": {}, + "MULMONTMAX": {}, +} + +def gen_push_word(item: int) -> str: + pass + +def gen_mstore(dst: int) -> str: + pass + +def calc_limb_count(num: int) -> int: + pass + +def gen_setmod(mod: int, slot: int) -> str: + assert mod % 2 != 0, "modulus must be odd" + assert (len(hex(mod)) - 2) / 64 < MAX_LIMBS, "modulus would occupy more than MAX_LIMBS 64bit limbs" + assert slot < 256 and slot >= 0, "slot must be gte to 0 and less than 256" + + evmmax_limb_count = calc_limb_count(mod) + evm_words = [] + offset = slot * evmmax_limb_count + result = "" + + for word in evm_words: + result += gen_push_word(word) + gen_mstore(offset) + + return result + +def gen_evmmax_op_loop_body(op: str, num_iterations: int) -> str: + pass + +def gen_push3_pop_loop_body(num_iterations: int) -> str: + result = "" + for i in range(num_iterations): + result += gen_push3_zero() + gen_pop() + +def gen_push3_pop_loop_benchmark() -> str: + return gen_loop().format(gen_push3_pop_loop_body(PUSH3_POP_ITER_COUNT)) + +def gen_loop() -> str: + return "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01{}60010180602157" + +def gen_arith_loop_benchmark(op: str) -> str: + pass + +def main(): + for op_name in EVMMAX_OPS.keys(): + with open("benchmarks/{}-loop.hex", "w") as f: + f.write(gen_arith_loop_benchmark(op_name)) + + with open("benchmarks/push3-pop-loop.hex", "w") as f: + f.write(gen_push3_pop_loop_benchmark()) + +if __name__ == "__main__": + main() From 45fd35c9124b9f22e629aa738aa76073974d578b Mon Sep 17 00:00:00 2001 From: Jared Wasinger Date: Sat, 30 Jul 2022 16:36:00 -0400 Subject: [PATCH 02/12] wip --- evmmax_generator/generate.py | 62 +++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/evmmax_generator/generate.py b/evmmax_generator/generate.py index a086cf4..9e5d05d 100644 --- a/evmmax_generator/generate.py +++ b/evmmax_generator/generate.py @@ -6,13 +6,39 @@ raise Exception("TODO^") EVMMAX_ARITH_OPS = { - "ADDMODMAX": {}, - "SUBMODMAX": {}, - "MULMONTMAX": {}, + "SETMODMAX": "0c", + "ADDMODMAX": "0d", + "SUBMODMAX": "0e", + "MULMONTMAX": "0f", } -def gen_push_word(item: int) -> str: - pass +# convert an int a little-endian list of 64bit-value limbs +def int_to_evmmax_limbs(val: int, limb_count: int) -> [int]: + if val == 0: + return [0] * limb_count + + result = [] + while val != 0: + limb = val % (1 << 64) + val >>= 64 + result.push(limb) + + if len(result) < limb_count: + result = result + [0] * (limb_count - len(result)) + return result + +def gen_mstore_evmmax_elem(val: int) -> str: + limbs = int_to_evmmax_limbs(item) + evm_word = "" + for i in range(limbs): + import pdb; pdb.set_trace() + evm_word += limbs[i] # TODO + if i != 0 and i % 4 == 0: + result += gen_mstore_word(evm_word, offset) + evm_word = 0 + offset += 32 + result += gen_mstore_word(evm_word, offset) + return result def gen_mstore(dst: int) -> str: pass @@ -35,22 +61,34 @@ def gen_setmod(mod: int, slot: int) -> str: return result -def gen_evmmax_op_loop_body(op: str, num_iterations: int) -> str: - pass - def gen_push3_pop_loop_body(num_iterations: int) -> str: result = "" for i in range(num_iterations): result += gen_push3_zero() + gen_pop() def gen_push3_pop_loop_benchmark() -> str: - return gen_loop().format(gen_push3_pop_loop_body(PUSH3_POP_ITER_COUNT)) + return gen_loop().format("", gen_push3_pop_loop_body(PUSH3_POP_ITER_COUNT)) def gen_loop() -> str: - return "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01{}60010180602157" + return "{}7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01{}60010180602157" -def gen_arith_loop_benchmark(op: str) -> str: - pass +def gen_arith_loop_benchmark(op: str, limb_count: str) -> str: + mod = gen_mod(limb_count) + setmod = gen_setmod(mod, 0) + + end_mem = limb_count * 8 * 4 # the offset of the first word beyond the end of the last slot we will use + expandmemory = gen_push_int(end_mem) + gen_push_word(0) + gen_mstore() + + x_input, y_input = gen_evmmax_worst_input(op, limb_count) + store_inputs = gen_mstore_evmmax_input(1, x_input) + gen_mstore_evmmax_input(2, y_input) + + bench_start = setmod + expand_memory + store_inputs + loop_body = "" + + for i in range(EVMMAX_ARITH_ITER_COUNT): + loop_body += gen_evmmax_op(op, 0, 1, 2) + + return gen_loop().format(bench_start, loop_body) def main(): for op_name in EVMMAX_OPS.keys(): From ec26540cd165689b232d642eb6a1c942a452b889 Mon Sep 17 00:00:00 2001 From: Jared Wasinger Date: Sat, 30 Jul 2022 17:39:15 -0400 Subject: [PATCH 03/12] wip --- evmmax_generator/generate.py | 117 +++++++++++++++++++---------------- 1 file changed, 63 insertions(+), 54 deletions(-) diff --git a/evmmax_generator/generate.py b/evmmax_generator/generate.py index 9e5d05d..6a64301 100644 --- a/evmmax_generator/generate.py +++ b/evmmax_generator/generate.py @@ -1,9 +1,14 @@ MAX_LIMBS = 11 -PUSH3_POP_ITER_COUNT = 0 -EVMMAX_ARITH_ITER_COUNT = 0 -raise Exception("TODO^") +EVMMAX_ARITH_OPS = { + "SETMODMAX": "0c", + "ADDMODMAX": "0d", + "SUBMODMAX": "0e", + "MULMONTMAX": "0f", +} + +LIMB_SIZE = 8 EVMMAX_ARITH_OPS = { "SETMODMAX": "0c", @@ -12,8 +17,28 @@ "MULMONTMAX": "0f", } +EVM_OPS = { + "MSTORE": "52" # TODO +} + +def pad_be_limb(word: str): + assert len(word) <= LIMB_SIZE * 2, "invalid length" + + if len(word) < LIMB_SIZE * 2: + return '0'*(LIMB_SIZE * 2 - len(word)) + word + else: + return word + +def reverse_endianess(word: str): + assert len(word) == LIMB_SIZE * 2, "invalid length" + + result = "" + for i in reversed(range(0, len(word), 2)): + result += word[i:i+2] + return result + # convert an int a little-endian list of 64bit-value limbs -def int_to_evmmax_limbs(val: int, limb_count: int) -> [int]: +def int_to_be_limbs(val: int, limb_count: int) -> [int]: if val == 0: return [0] * limb_count @@ -21,56 +46,47 @@ def int_to_evmmax_limbs(val: int, limb_count: int) -> [int]: while val != 0: limb = val % (1 << 64) val >>= 64 - result.push(limb) + result.append(hex(limb)[2:]) if len(result) < limb_count: - result = result + [0] * (limb_count - len(result)) - return result - -def gen_mstore_evmmax_elem(val: int) -> str: - limbs = int_to_evmmax_limbs(item) - evm_word = "" - for i in range(limbs): - import pdb; pdb.set_trace() - evm_word += limbs[i] # TODO - if i != 0 and i % 4 == 0: - result += gen_mstore_word(evm_word, offset) - evm_word = 0 - offset += 32 - result += gen_mstore_word(evm_word, offset) - return result + result = [0] * (limb_count - len(result)) + result -def gen_mstore(dst: int) -> str: - pass + return [pad_be_limb(limb) for limb in reversed(result)] -def calc_limb_count(num: int) -> int: - pass +def gen_push_int(val: int) -> str: + literal = hex(val)[2:] + if len(literal) % 2 == 1: + literal = "0" + literal + return gen_push_literal(literal) -def gen_setmod(mod: int, slot: int) -> str: - assert mod % 2 != 0, "modulus must be odd" - assert (len(hex(mod)) - 2) / 64 < MAX_LIMBS, "modulus would occupy more than MAX_LIMBS 64bit limbs" - assert slot < 256 and slot >= 0, "slot must be gte to 0 and less than 256" +def gen_push_literal(val: str) -> str: + assert len(val) <= 64, "val is too big" + assert len(val) % 2 == 0, "val must be even length" + push_start = 0x60 + push_op = hex(push_start - 1 + int(len(val) / 2))[2:] - evmmax_limb_count = calc_limb_count(mod) - evm_words = [] - offset = slot * evmmax_limb_count - result = "" - - for word in evm_words: - result += gen_push_word(word) + gen_mstore(offset) + assert len(push_op) == 2, "bug" - return result + return push_op + val -def gen_push3_pop_loop_body(num_iterations: int) -> str: - result = "" - for i in range(num_iterations): - result += gen_push3_zero() + gen_pop() +def gen_mstore_literal(val: str, offset: int) -> str: + return gen_push_literal(val) + gen_push_int(offset) + EVM_OPS["MSTORE"] -def gen_push3_pop_loop_benchmark() -> str: - return gen_loop().format("", gen_push3_pop_loop_body(PUSH3_POP_ITER_COUNT)) +def gen_mstore_evmmax_elem(dst_slot: int, val: int, limb_count: int) -> str: + assert dst_slot >= 0 and dst_slot < 11, "invalid dst_slot" -def gen_loop() -> str: - return "{}7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01{}60010180602157" + limbs = int_to_be_limbs(val, limb_count) + evm_word = "" + result = "" + offset = dst_slot * limb_count * LIMB_SIZE + for i in range(len(limbs)): + evm_word += limbs[i] + if i != 0 and i % 4 == 0: + result += gen_mstore_literal(evm_word, offset) + evm_word = "" + offset += 32 + result += gen_mstore_literal(evm_word, offset) + return result def gen_arith_loop_benchmark(op: str, limb_count: str) -> str: mod = gen_mod(limb_count) @@ -90,13 +106,6 @@ def gen_arith_loop_benchmark(op: str, limb_count: str) -> str: return gen_loop().format(bench_start, loop_body) -def main(): - for op_name in EVMMAX_OPS.keys(): - with open("benchmarks/{}-loop.hex", "w") as f: - f.write(gen_arith_loop_benchmark(op_name)) - - with open("benchmarks/push3-pop-loop.hex", "w") as f: - f.write(gen_push3_pop_loop_benchmark()) - -if __name__ == "__main__": - main() +def gen_loop() -> str: + return "{}7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01{}60010180602157" +import pdb; pdb.set_trace() From f034875165e8ed437dd61baeeed04c618ca1a651 Mon Sep 17 00:00:00 2001 From: Jared Wasinger Date: Sat, 30 Jul 2022 18:10:42 -0400 Subject: [PATCH 04/12] wip --- evmmax_generator/generate.py | 65 +++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 8 deletions(-) diff --git a/evmmax_generator/generate.py b/evmmax_generator/generate.py index 6a64301..dbbe9f2 100644 --- a/evmmax_generator/generate.py +++ b/evmmax_generator/generate.py @@ -1,4 +1,6 @@ +EVMMAX_ARITH_ITER_COUNT = 1 + MAX_LIMBS = 11 EVMMAX_ARITH_OPS = { @@ -10,8 +12,9 @@ LIMB_SIZE = 8 +SETMOD_OP = "0c" + EVMMAX_ARITH_OPS = { - "SETMODMAX": "0c", "ADDMODMAX": "0d", "SUBMODMAX": "0e", "MULMONTMAX": "0f", @@ -37,10 +40,19 @@ def reverse_endianess(word: str): result += word[i:i+2] return result +def calc_limb_count(val: int) -> int: + assert val > 0, "val must be greater than 0" + + count = 0 + while val != 0: + val >>= 64 + count += 1 + return count + # convert an int a little-endian list of 64bit-value limbs def int_to_be_limbs(val: int, limb_count: int) -> [int]: if val == 0: - return [0] * limb_count + return ['00'] * limb_count result = [] while val != 0: @@ -54,6 +66,8 @@ def int_to_be_limbs(val: int, limb_count: int) -> [int]: return [pad_be_limb(limb) for limb in reversed(result)] def gen_push_int(val: int) -> str: + assert val >= 0 and val < (1 << 256), "val must be in acceptable evm word range" + literal = hex(val)[2:] if len(literal) % 2 == 1: literal = "0" + literal @@ -69,6 +83,9 @@ def gen_push_literal(val: str) -> str: return push_op + val +def gen_mstore_int(val: int, offset: int) -> str: + return gen_push_int(val) + gen_push_int(offset) + EVM_OPS["MSTORE"] + def gen_mstore_literal(val: str, offset: int) -> str: return gen_push_literal(val) + gen_push_int(offset) + EVM_OPS["MSTORE"] @@ -80,25 +97,55 @@ def gen_mstore_evmmax_elem(dst_slot: int, val: int, limb_count: int) -> str: result = "" offset = dst_slot * limb_count * LIMB_SIZE for i in range(len(limbs)): - evm_word += limbs[i] if i != 0 and i % 4 == 0: result += gen_mstore_literal(evm_word, offset) - evm_word = "" + evm_word = limbs[i] offset += 32 + else: + evm_word += limbs[i] result += gen_mstore_literal(evm_word, offset) return result +def gen_encode_evmmax_bytes(*args): + result = "" + for b1 in args: + assert b1 >= 0 and b1 < 256, "argument must be in byte range" + + b1 = hex(b1)[2:] + if len(b1) == 1: + b1 = '0'+b1 + + result += b1 + return result + +def gen_setmod(slot: int, mod: int) -> str: + limb_count = calc_limb_count(mod) + result = gen_mstore_evmmax_elem(slot, mod, limb_count) + result += gen_push_literal(gen_encode_evmmax_bytes(0, limb_count)) + result += SETMOD_OP + return result + +# return largest-possible mod representable with a given limb count +def gen_mod(limb_count: int) -> int: + return (1 << (limb_count * LIMB_SIZE * 8)) - 1 + +def gen_evmmax_worst_input(op: str, limb_count: int) -> (int, int): + return 0, 0 + +def gen_evmmax_op(op: str, out_slot: int, x_slot: int, y_slot: int) -> str: + return gen_push_literal(gen_encode_evmmax_bytes(out_slot, x_slot, y_slot)) + EVMMAX_ARITH_OPS[op] + def gen_arith_loop_benchmark(op: str, limb_count: str) -> str: mod = gen_mod(limb_count) - setmod = gen_setmod(mod, 0) + setmod = gen_setmod(0, mod) end_mem = limb_count * 8 * 4 # the offset of the first word beyond the end of the last slot we will use - expandmemory = gen_push_int(end_mem) + gen_push_word(0) + gen_mstore() + expand_memory = gen_mstore_int(end_mem, 0) x_input, y_input = gen_evmmax_worst_input(op, limb_count) - store_inputs = gen_mstore_evmmax_input(1, x_input) + gen_mstore_evmmax_input(2, y_input) + store_inputs = gen_mstore_evmmax_elem(1, x_input, limb_count) + gen_mstore_evmmax_elem(2, y_input, limb_count) - bench_start = setmod + expand_memory + store_inputs + bench_start = expand_memory + setmod + store_inputs loop_body = "" for i in range(EVMMAX_ARITH_ITER_COUNT): @@ -108,4 +155,6 @@ def gen_arith_loop_benchmark(op: str, limb_count: str) -> str: def gen_loop() -> str: return "{}7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01{}60010180602157" + +res = gen_arith_loop_benchmark("MULMONTMAX", 5) import pdb; pdb.set_trace() From 5394f0241cdb1a49b0c15cf41f05ed2636cb5a4e Mon Sep 17 00:00:00 2001 From: Jared Wasinger Date: Sat, 30 Jul 2022 21:37:27 -0400 Subject: [PATCH 05/12] wip: mulmont appears to work now --- evmmax_generator/generate.py | 48 ++++++++++++++++++++++++++++-------- evmmax_generator/test.sh | 3 +++ 2 files changed, 41 insertions(+), 10 deletions(-) create mode 100755 evmmax_generator/test.sh diff --git a/evmmax_generator/generate.py b/evmmax_generator/generate.py index dbbe9f2..8ec57ea 100644 --- a/evmmax_generator/generate.py +++ b/evmmax_generator/generate.py @@ -1,3 +1,4 @@ +import math EVMMAX_ARITH_ITER_COUNT = 1 @@ -58,10 +59,13 @@ def int_to_be_limbs(val: int, limb_count: int) -> [int]: while val != 0: limb = val % (1 << 64) val >>= 64 - result.append(hex(limb)[2:]) + limb_hex = hex(limb)[2:] + if len(limb_hex) < LIMB_SIZE * 2: + limb_hex = ((LIMB_SIZE * 2) - len(limb_hex)) * '0' + limb_hex + result.append(limb_hex) if len(result) < limb_count: - result = [0] * (limb_count - len(result)) + result + result = result + ['0'] * (limb_count - len(result)) return [pad_be_limb(limb) for limb in reversed(result)] @@ -99,10 +103,13 @@ def gen_mstore_evmmax_elem(dst_slot: int, val: int, limb_count: int) -> str: for i in range(len(limbs)): if i != 0 and i % 4 == 0: result += gen_mstore_literal(evm_word, offset) - evm_word = limbs[i] + evm_word = limbs[len(limbs) - i - 1] offset += 32 else: - evm_word += limbs[i] + evm_word += limbs[len(limbs) - i - 1] + + if len(evm_word) < 64: + evm_word = evm_word + "0" * (64 - len(evm_word)) result += gen_mstore_literal(evm_word, offset) return result @@ -121,16 +128,37 @@ def gen_encode_evmmax_bytes(*args): def gen_setmod(slot: int, mod: int) -> str: limb_count = calc_limb_count(mod) result = gen_mstore_evmmax_elem(slot, mod, limb_count) - result += gen_push_literal(gen_encode_evmmax_bytes(0, limb_count)) + result += gen_push_literal(gen_encode_evmmax_bytes(limb_count, slot)) result += SETMOD_OP return result -# return largest-possible mod representable with a given limb count +# return modulus roughly in the middle of the range that can be represented with limb_count def gen_mod(limb_count: int) -> int: - return (1 << (limb_count * LIMB_SIZE * 8)) - 1 + mod = (1 << ((limb_count - 1) * LIMB_SIZE * 8) + int((LIMB_SIZE * 8) / 2)) - 1 + return mod +def worst_case_mulmontmax_input(limb_count: int) -> int: + mod = gen_mod(limb_count) + r = 1 << (limb_count * LIMB_SIZE * 8) + r_inv = pow(-mod, -1, r) + + # res = math.ceil(math.sqrt((mod * r) / (mod * r_inv + 1))) + return mod - 1#res + +# generate the slowest inputs for the maximum modulus representable by limb_count limbs def gen_evmmax_worst_input(op: str, limb_count: int) -> (int, int): - return 0, 0 + if op == "MULMONTMAX": + # TODO generate inputs to make the final subtraction happen + # want ((x * y * n_inv) * mod + x * y) / R < N + val = worst_case_mulmontmax_input(limb_count) + # TODO yoloing here + return val, val>>16 + elif op == "ADDMODMAX": + pass + elif op == "SUBMODMAX": + pass + else: + raise Exception("unknown evmmax arith op") def gen_evmmax_op(op: str, out_slot: int, x_slot: int, y_slot: int) -> str: return gen_push_literal(gen_encode_evmmax_bytes(out_slot, x_slot, y_slot)) + EVMMAX_ARITH_OPS[op] @@ -143,6 +171,7 @@ def gen_arith_loop_benchmark(op: str, limb_count: str) -> str: expand_memory = gen_mstore_int(end_mem, 0) x_input, y_input = gen_evmmax_worst_input(op, limb_count) + #import pdb; pdb.set_trace() store_inputs = gen_mstore_evmmax_elem(1, x_input, limb_count) + gen_mstore_evmmax_elem(2, y_input, limb_count) bench_start = expand_memory + setmod + store_inputs @@ -156,5 +185,4 @@ def gen_arith_loop_benchmark(op: str, limb_count: str) -> str: def gen_loop() -> str: return "{}7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01{}60010180602157" -res = gen_arith_loop_benchmark("MULMONTMAX", 5) -import pdb; pdb.set_trace() +print("0x"+gen_arith_loop_benchmark("MULMONTMAX", 5)) diff --git a/evmmax_generator/test.sh b/evmmax_generator/test.sh new file mode 100755 index 0000000..fdfe2b9 --- /dev/null +++ b/evmmax_generator/test.sh @@ -0,0 +1,3 @@ +#! /usr/bin/env bash + +~/projects/go-ethereum-evmmax-no-eof/build/bin/evm --nomemory=false --code $(python3 generate.py) --json run From 91e26f6edb6950a435cade0c964895c15aecdec7 Mon Sep 17 00:00:00 2001 From: Jared Wasinger Date: Sat, 30 Jul 2022 22:03:11 -0400 Subject: [PATCH 06/12] wip --- evmmax_generator/generate.py | 15 ++++++++++++--- evmmax_generator/test.sh | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/evmmax_generator/generate.py b/evmmax_generator/generate.py index 8ec57ea..decb08e 100644 --- a/evmmax_generator/generate.py +++ b/evmmax_generator/generate.py @@ -163,6 +163,8 @@ def gen_evmmax_worst_input(op: str, limb_count: int) -> (int, int): def gen_evmmax_op(op: str, out_slot: int, x_slot: int, y_slot: int) -> str: return gen_push_literal(gen_encode_evmmax_bytes(out_slot, x_slot, y_slot)) + EVMMAX_ARITH_OPS[op] +MAX_CONTRACT_SIZE = 24576 + def gen_arith_loop_benchmark(op: str, limb_count: str) -> str: mod = gen_mod(limb_count) setmod = gen_setmod(0, mod) @@ -177,12 +179,19 @@ def gen_arith_loop_benchmark(op: str, limb_count: str) -> str: bench_start = expand_memory + setmod + store_inputs loop_body = "" - for i in range(EVMMAX_ARITH_ITER_COUNT): + empty_bench_len = int(len(gen_loop().format(bench_start, "", gen_push_int(258))) / 2) + free_size = MAX_CONTRACT_SIZE - empty_bench_len + iter_size = 5 # PUSH3 + 3byte immediate + EVMMAX_ARITH_OPCODE + iter_count = math.floor(free_size / 5) + for i in range(iter_count): loop_body += gen_evmmax_op(op, 0, 1, 2) - return gen_loop().format(bench_start, loop_body) + # TODO don't hardcode jumpdest pc (258) + res = gen_loop().format(bench_start, loop_body, gen_push_int(258)) + assert len(res) / 2 <= MAX_CONTRACT_SIZE, "benchmark greater than max contract size" + return res def gen_loop() -> str: - return "{}7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01{}60010180602157" + return "{}7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff015b{}60010180{}57" print("0x"+gen_arith_loop_benchmark("MULMONTMAX", 5)) diff --git a/evmmax_generator/test.sh b/evmmax_generator/test.sh index fdfe2b9..6d25d57 100755 --- a/evmmax_generator/test.sh +++ b/evmmax_generator/test.sh @@ -1,3 +1,3 @@ #! /usr/bin/env bash -~/projects/go-ethereum-evmmax-no-eof/build/bin/evm --nomemory=false --code $(python3 generate.py) --json run +~/projects/go-ethereum-evmmax-no-eof/build/bin/evm --code $(python3 generate.py) run From 19d576c393d839db4b66bed8b6c8b411ebbf95c4 Mon Sep 17 00:00:00 2001 From: Jared Wasinger Date: Mon, 1 Aug 2022 01:28:46 -0400 Subject: [PATCH 07/12] wip --- evmmax_generator/generate.py | 160 ++++++++++++++++++++++++----------- 1 file changed, 110 insertions(+), 50 deletions(-) diff --git a/evmmax_generator/generate.py b/evmmax_generator/generate.py index decb08e..7d4735e 100644 --- a/evmmax_generator/generate.py +++ b/evmmax_generator/generate.py @@ -1,4 +1,7 @@ import math +import os +import sys +import subprocess EVMMAX_ARITH_ITER_COUNT = 1 @@ -25,14 +28,6 @@ "MSTORE": "52" # TODO } -def pad_be_limb(word: str): - assert len(word) <= LIMB_SIZE * 2, "invalid length" - - if len(word) < LIMB_SIZE * 2: - return '0'*(LIMB_SIZE * 2 - len(word)) + word - else: - return word - def reverse_endianess(word: str): assert len(word) == LIMB_SIZE * 2, "invalid length" @@ -50,24 +45,35 @@ def calc_limb_count(val: int) -> int: count += 1 return count -# convert an int a little-endian list of 64bit-value limbs -def int_to_be_limbs(val: int, limb_count: int) -> [int]: +# split a value into 256bit big-endian words, return them in little-endian format +def int_to_evm_words(val: int, evm384_limb_count: int) -> [str]: + result = [] if val == 0: - return ['00'] * limb_count + return ['00'] - result = [] + og_val = val while val != 0: - limb = val % (1 << 64) - val >>= 64 + limb = val % (1 << 256) + val >>= 256 + + if limb == 0: + result.append("00") + continue + limb_hex = hex(limb)[2:] - if len(limb_hex) < LIMB_SIZE * 2: - limb_hex = ((LIMB_SIZE * 2) - len(limb_hex)) * '0' + limb_hex + if len(limb_hex) % 2 != 0: + limb_hex = "0" + limb_hex + + limb_hex = reverse_endianess(limb_hex) + if len(limb_hex) < 64: + limb_hex += (64 - len(limb_hex)) * "0" + result.append(limb_hex) - if len(result) < limb_count: - result = result + ['0'] * (limb_count - len(result)) + if len(result) * 32 < evm384_limb_count * LIMB_SIZE: + result = ['00'] * math.ceil((limb_count * LIMB_SIZE - len(result) * 32) / 32) + result - return [pad_be_limb(limb) for limb in reversed(result)] + return list(reversed(result)) def gen_push_int(val: int) -> str: assert val >= 0 and val < (1 << 256), "val must be in acceptable evm word range" @@ -93,24 +99,24 @@ def gen_mstore_int(val: int, offset: int) -> str: def gen_mstore_literal(val: str, offset: int) -> str: return gen_push_literal(val) + gen_push_int(offset) + EVM_OPS["MSTORE"] +def reverse_endianess(val: str): + assert len(val) % 2 == 0, "must have even string" + result = "" + for i in reversed(range(0, len(val), 2)): + result += val[i:i+2] + + return result + def gen_mstore_evmmax_elem(dst_slot: int, val: int, limb_count: int) -> str: assert dst_slot >= 0 and dst_slot < 11, "invalid dst_slot" - limbs = int_to_be_limbs(val, limb_count) - evm_word = "" + evm_words = int_to_evm_words(val, limb_count) result = "" offset = dst_slot * limb_count * LIMB_SIZE - for i in range(len(limbs)): - if i != 0 and i % 4 == 0: - result += gen_mstore_literal(evm_word, offset) - evm_word = limbs[len(limbs) - i - 1] - offset += 32 - else: - evm_word += limbs[len(limbs) - i - 1] - - if len(evm_word) < 64: - evm_word = evm_word + "0" * (64 - len(evm_word)) - result += gen_mstore_literal(evm_word, offset) + for word in evm_words: + result += gen_mstore_literal(word, offset) + offset += 32 + return result def gen_encode_evmmax_bytes(*args): @@ -134,29 +140,39 @@ def gen_setmod(slot: int, mod: int) -> str: # return modulus roughly in the middle of the range that can be represented with limb_count def gen_mod(limb_count: int) -> int: - mod = (1 << ((limb_count - 1) * LIMB_SIZE * 8) + int((LIMB_SIZE * 8) / 2)) - 1 + mod = (1 << ((limb_count - 1) * LIMB_SIZE * 8 + 8)) - 1 return mod -def worst_case_mulmontmax_input(limb_count: int) -> int: +def worst_case_mulmontmax_input(limb_count: int) -> (int, int): mod = gen_mod(limb_count) r = 1 << (limb_count * LIMB_SIZE * 8) r_inv = pow(-mod, -1, r) - # res = math.ceil(math.sqrt((mod * r) / (mod * r_inv + 1))) - return mod - 1#res + # TODO figure this out + + # choose x == y: (x**2 * n_inv * mod + x ** 2) / R < N + #return res + # import pdb; pdb.set_trace() + return mod - 1, mod - 1 + +def worst_case_addmodmax_inputs(limb_count: int) -> (int, int): + mod = gen_mod(limb_count) + x = mod - 2 + + return x, 1 + +def worst_case_submodmax_inputs(limb_count: int) -> (int, int): + return 1, 0 # generate the slowest inputs for the maximum modulus representable by limb_count limbs def gen_evmmax_worst_input(op: str, limb_count: int) -> (int, int): if op == "MULMONTMAX": # TODO generate inputs to make the final subtraction happen - # want ((x * y * n_inv) * mod + x * y) / R < N - val = worst_case_mulmontmax_input(limb_count) - # TODO yoloing here - return val, val>>16 + return worst_case_mulmontmax_input(limb_count) elif op == "ADDMODMAX": - pass + return worst_case_addmodmax_inputs(limb_count) elif op == "SUBMODMAX": - pass + return worst_case_submodmax_inputs(limb_count) else: raise Exception("unknown evmmax arith op") @@ -169,29 +185,73 @@ def gen_arith_loop_benchmark(op: str, limb_count: str) -> str: mod = gen_mod(limb_count) setmod = gen_setmod(0, mod) - end_mem = limb_count * 8 * 4 # the offset of the first word beyond the end of the last slot we will use - expand_memory = gen_mstore_int(end_mem, 0) + # mod_mem = limb_count * 8 * 4 # the offset of the first word beyond the end of the last slot we will use + # expand_memory = gen_mstore_int(end_mem, 0) x_input, y_input = gen_evmmax_worst_input(op, limb_count) - #import pdb; pdb.set_trace() store_inputs = gen_mstore_evmmax_elem(1, x_input, limb_count) + gen_mstore_evmmax_elem(2, y_input, limb_count) - bench_start = expand_memory + setmod + store_inputs + bench_start = setmod + store_inputs loop_body = "" empty_bench_len = int(len(gen_loop().format(bench_start, "", gen_push_int(258))) / 2) free_size = MAX_CONTRACT_SIZE - empty_bench_len iter_size = 5 # PUSH3 + 3byte immediate + EVMMAX_ARITH_OPCODE iter_count = math.floor(free_size / 5) + + inner_loop_evmmax_op_count = 0 + for i in range(iter_count): loop_body += gen_evmmax_op(op, 0, 1, 2) + inner_loop_evmmax_op_count += 1 + + loop_iterations = 256 # TODO verify this + inner_loop_evmmax_op_count *= loop_iterations - # TODO don't hardcode jumpdest pc (258) - res = gen_loop().format(bench_start, loop_body, gen_push_int(258)) + res = gen_loop().format(bench_start, loop_body, gen_push_int(int(len(bench_start) / 2) + 33)) assert len(res) / 2 <= MAX_CONTRACT_SIZE, "benchmark greater than max contract size" - return res + return res, inner_loop_evmmax_op_count def gen_loop() -> str: return "{}7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff015b{}60010180{}57" -print("0x"+gen_arith_loop_benchmark("MULMONTMAX", 5)) +def bench_geth_evmmax(arith_op_name: str, limb_count: int) -> (int, int): + bench_code, evmmax_op_count = gen_arith_loop_benchmark(arith_op_name, limb_count) + geth_exec = os.path.join(os.getcwd(), "go-ethereum/build/bin/evm") + geth_cmd = "{} --code {} --bench run".format(geth_exec, bench_code) + result = subprocess.run(geth_cmd.split(' '), stdout=subprocess.PIPE, stderr=subprocess.PIPE) + if result.returncode != 0: + raise Exception("geth exec error: {}".format(result.stderr)) + + exec_time = str(result.stderr).split('\\n')[1].strip('execution time: ') + + if exec_time.endswith("ms"): + exec_time = int(float(exec_time[:-2]) * 1000000) + elif exec_time.endswith("s"): + exec_time = int(float(exec_time[:-1]) * 1000000 * 1000) + else: + raise Exception("unknown timestamp ending: {}".format(exec_time)) + + return exec_time, evmmax_op_count + +if __name__ == "__main__": + #if len(sys.argv[1:]) != 2: + # raise Exception("must provide inputs op (MULMONTMAX,ADDMODMAX,SUBMODMAX) limbCount (1-11)") + + #op = sys.argv[1] + #if op != "ADDMODMAX" and op != "SUBMODMAX" and op != "MULMONTMAX": + # raise Exception("unknown op") + + #limb_count = int(sys.argv[2]) + #if limb_count < 0 or limb_count > 11: + # raise Exception("must choose limb count between 1 and 11") + + for arith_op_name in ["ADDMODMAX", "SUBMODMAX", "MULMONTMAX"]: + for limb_count in range(1,12): + evmmax_bench_time, evmmax_op_count = bench_geth_evmmax(arith_op_name, limb_count) + + push3_pop_bench_time = 0 # TODO bench_geth_push3_pop(evmmax_op_count) + setmod_est_time = 0 # TODO + + est_time = (evmmax_bench_time - push3_pop_bench_time - setmod_est_time) / evmmax_op_count + print("{} - {} limbs - {} ns/op".format(arith_op_name, limb_count, est_time)) From 636ae28ea8f0999f0ef2f6afa385f782ca74fdff Mon Sep 17 00:00:00 2001 From: Jared Wasinger Date: Mon, 1 Aug 2022 02:38:10 -0400 Subject: [PATCH 08/12] update --- .gitmodules | 3 +++ evmmax_generator/generate.py | 38 +++++++++++++++++++++++++----------- evmmax_generator/go-ethereum | 1 + evmmax_generator/test.sh | 3 --- 4 files changed, 31 insertions(+), 14 deletions(-) create mode 100644 .gitmodules create mode 160000 evmmax_generator/go-ethereum delete mode 100755 evmmax_generator/test.sh diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..a4e177d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "evmmax_generator/go-ethereum"] + path = evmmax_generator/go-ethereum + url = https://github.com/jwasinger/go-ethereum diff --git a/evmmax_generator/generate.py b/evmmax_generator/generate.py index 7d4735e..aab4f4e 100644 --- a/evmmax_generator/generate.py +++ b/evmmax_generator/generate.py @@ -25,7 +25,8 @@ } EVM_OPS = { - "MSTORE": "52" # TODO + "POP": "50", + "MSTORE": "52", } def reverse_endianess(word: str): @@ -205,20 +206,26 @@ def gen_arith_loop_benchmark(op: str, limb_count: str) -> str: loop_body += gen_evmmax_op(op, 0, 1, 2) inner_loop_evmmax_op_count += 1 - loop_iterations = 256 # TODO verify this - inner_loop_evmmax_op_count *= loop_iterations - res = gen_loop().format(bench_start, loop_body, gen_push_int(int(len(bench_start) / 2) + 33)) assert len(res) / 2 <= MAX_CONTRACT_SIZE, "benchmark greater than max contract size" - return res, inner_loop_evmmax_op_count + return res, inner_loop_evmmax_op_count def gen_loop() -> str: return "{}7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff015b{}60010180{}57" -def bench_geth_evmmax(arith_op_name: str, limb_count: int) -> (int, int): - bench_code, evmmax_op_count = gen_arith_loop_benchmark(arith_op_name, limb_count) +def gen_push3_pop_loop_benchmark(count: int) -> str: + loop_body = "" + for i in range(count): + loop_body += gen_push_literal(gen_encode_evmmax_bytes(1, 2, 3)) + loop_body += EVM_OPS["POP"] + + return gen_loop().format("", loop_body, gen_push_int(33)) + +# bench some evm bytecode and return the runtime in ns + +def bench_geth(code: str) -> int: geth_exec = os.path.join(os.getcwd(), "go-ethereum/build/bin/evm") - geth_cmd = "{} --code {} --bench run".format(geth_exec, bench_code) + geth_cmd = "{} --code {} --bench run".format(geth_exec, code) result = subprocess.run(geth_cmd.split(' '), stdout=subprocess.PIPE, stderr=subprocess.PIPE) if result.returncode != 0: raise Exception("geth exec error: {}".format(result.stderr)) @@ -232,7 +239,13 @@ def bench_geth_evmmax(arith_op_name: str, limb_count: int) -> (int, int): else: raise Exception("unknown timestamp ending: {}".format(exec_time)) - return exec_time, evmmax_op_count + return exec_time + +def bench_geth_evmmax(arith_op_name: str, limb_count: int) -> (int, int): + bench_code, evmmax_op_count = gen_arith_loop_benchmark(arith_op_name, limb_count) + + return bench_geth(bench_code), evmmax_op_count + if __name__ == "__main__": #if len(sys.argv[1:]) != 2: @@ -246,12 +259,15 @@ def bench_geth_evmmax(arith_op_name: str, limb_count: int) -> (int, int): #if limb_count < 0 or limb_count > 11: # raise Exception("must choose limb count between 1 and 11") + LOOP_ITERATIONS = 256 # TODO check this + for arith_op_name in ["ADDMODMAX", "SUBMODMAX", "MULMONTMAX"]: for limb_count in range(1,12): evmmax_bench_time, evmmax_op_count = bench_geth_evmmax(arith_op_name, limb_count) - push3_pop_bench_time = 0 # TODO bench_geth_push3_pop(evmmax_op_count) + push3_pop_bench_time = bench_geth(gen_push3_pop_loop_benchmark(evmmax_op_count)) setmod_est_time = 0 # TODO - est_time = (evmmax_bench_time - push3_pop_bench_time - setmod_est_time) / evmmax_op_count + est_time = math.ceil((evmmax_bench_time - push3_pop_bench_time - setmod_est_time) / (evmmax_op_count * LOOP_ITERATIONS)) print("{} - {} limbs - {} ns/op".format(arith_op_name, limb_count, est_time)) + print() diff --git a/evmmax_generator/go-ethereum b/evmmax_generator/go-ethereum new file mode 160000 index 0000000..f0eb900 --- /dev/null +++ b/evmmax_generator/go-ethereum @@ -0,0 +1 @@ +Subproject commit f0eb900ae037c696c8d5b69bfe04a3c9f54e480f diff --git a/evmmax_generator/test.sh b/evmmax_generator/test.sh deleted file mode 100755 index 6d25d57..0000000 --- a/evmmax_generator/test.sh +++ /dev/null @@ -1,3 +0,0 @@ -#! /usr/bin/env bash - -~/projects/go-ethereum-evmmax-no-eof/build/bin/evm --code $(python3 generate.py) run From 90e518fec6b89fff864f0143992a0d407f32516e Mon Sep 17 00:00:00 2001 From: Jared Wasinger Date: Thu, 4 Aug 2022 01:07:55 -0400 Subject: [PATCH 09/12] wip --- evmmax_generator/generate.py | 62 +++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/evmmax_generator/generate.py b/evmmax_generator/generate.py index aab4f4e..134b15b 100644 --- a/evmmax_generator/generate.py +++ b/evmmax_generator/generate.py @@ -72,7 +72,7 @@ def int_to_evm_words(val: int, evm384_limb_count: int) -> [str]: result.append(limb_hex) if len(result) * 32 < evm384_limb_count * LIMB_SIZE: - result = ['00'] * math.ceil((limb_count * LIMB_SIZE - len(result) * 32) / 32) + result + result = ['00'] * math.ceil((evm384_limb_count * LIMB_SIZE - len(result) * 32) / 32) + result return list(reversed(result)) @@ -140,21 +140,22 @@ def gen_setmod(slot: int, mod: int) -> str: return result # return modulus roughly in the middle of the range that can be represented with limb_count +#def gen_mod(limb_count: int) -> int: +# mod = (1 << ((limb_count - 1) * LIMB_SIZE * 8 + 8)) - 1 +# return mod + def gen_mod(limb_count: int) -> int: - mod = (1 << ((limb_count - 1) * LIMB_SIZE * 8 + 8)) - 1 - return mod + return (1 << (limb_count * LIMB_SIZE * 8)) - 1 def worst_case_mulmontmax_input(limb_count: int) -> (int, int): mod = gen_mod(limb_count) r = 1 << (limb_count * LIMB_SIZE * 8) r_inv = pow(-mod, -1, r) - # TODO figure this out - - # choose x == y: (x**2 * n_inv * mod + x ** 2) / R < N - #return res - # import pdb; pdb.set_trace() - return mod - 1, mod - 1 + # TODO this is the "pseudo worst-case" input for the CIOS algorithm from gnark-crypto + # It does a final subtraction, but the final check if output>modulus is determined because + # the output occupies limb_count + 1 limbs + return 1, 1 def worst_case_addmodmax_inputs(limb_count: int) -> (int, int): mod = gen_mod(limb_count) @@ -198,7 +199,9 @@ def gen_arith_loop_benchmark(op: str, limb_count: str) -> str: empty_bench_len = int(len(gen_loop().format(bench_start, "", gen_push_int(258))) / 2) free_size = MAX_CONTRACT_SIZE - empty_bench_len iter_size = 5 # PUSH3 + 3byte immediate + EVMMAX_ARITH_OPCODE - iter_count = math.floor(free_size / 5) + # iter_count = math.floor(free_size / 5) + # import pdb; pdb.set_trace() + iter_count = 5000 inner_loop_evmmax_op_count = 0 @@ -207,7 +210,7 @@ def gen_arith_loop_benchmark(op: str, limb_count: str) -> str: inner_loop_evmmax_op_count += 1 res = gen_loop().format(bench_start, loop_body, gen_push_int(int(len(bench_start) / 2) + 33)) - assert len(res) / 2 <= MAX_CONTRACT_SIZE, "benchmark greater than max contract size" + # assert len(res) / 2 <= MAX_CONTRACT_SIZE, "benchmark greater than max contract size" return res, inner_loop_evmmax_op_count def gen_loop() -> str: @@ -247,21 +250,10 @@ def bench_geth_evmmax(arith_op_name: str, limb_count: int) -> (int, int): return bench_geth(bench_code), evmmax_op_count -if __name__ == "__main__": - #if len(sys.argv[1:]) != 2: - # raise Exception("must provide inputs op (MULMONTMAX,ADDMODMAX,SUBMODMAX) limbCount (1-11)") - - #op = sys.argv[1] - #if op != "ADDMODMAX" and op != "SUBMODMAX" and op != "MULMONTMAX": - # raise Exception("unknown op") - - #limb_count = int(sys.argv[2]) - #if limb_count < 0 or limb_count > 11: - # raise Exception("must choose limb count between 1 and 11") - - LOOP_ITERATIONS = 256 # TODO check this +def default_run(): + LOOP_ITERATIONS = 255 # TODO check this - for arith_op_name in ["ADDMODMAX", "SUBMODMAX", "MULMONTMAX"]: + for arith_op_name in ["MULMONTMAX"]: #["ADDMODMAX", "SUBMODMAX", "MULMONTMAX"]: for limb_count in range(1,12): evmmax_bench_time, evmmax_op_count = bench_geth_evmmax(arith_op_name, limb_count) @@ -271,3 +263,23 @@ def bench_geth_evmmax(arith_op_name: str, limb_count: int) -> (int, int): est_time = math.ceil((evmmax_bench_time - push3_pop_bench_time - setmod_est_time) / (evmmax_op_count * LOOP_ITERATIONS)) print("{} - {} limbs - {} ns/op".format(arith_op_name, limb_count, est_time)) print() + +if __name__ == "__main__": + if len(sys.argv) == 1: + default_run() + elif len(sys.argv) >= 2: + op = sys.argv[1] + if op != "ADDMODMAX" and op != "SUBMODMAX" and op != "MULMONTMAX": + raise Exception("unknown op") + + limb_count = int(sys.argv[2]) + if limb_count < 0 or limb_count > 11: + raise Exception("must choose limb count between 1 and 11") + + if sys.argv[3] == "dumpgethcmd": + bench_code, evmmax_op_count = gen_arith_loop_benchmark(op, limb_count) + print(bench_code) + + else: + print("too many args") + From 0fe304a496fe89da60255f580047346722d6091d Mon Sep 17 00:00:00 2001 From: Jared Wasinger Date: Thu, 4 Aug 2022 04:18:44 -0400 Subject: [PATCH 10/12] update --- evmmax_generator/generate.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/evmmax_generator/generate.py b/evmmax_generator/generate.py index 134b15b..c6c1ed8 100644 --- a/evmmax_generator/generate.py +++ b/evmmax_generator/generate.py @@ -192,8 +192,11 @@ def gen_arith_loop_benchmark(op: str, limb_count: str) -> str: x_input, y_input = gen_evmmax_worst_input(op, limb_count) store_inputs = gen_mstore_evmmax_elem(1, x_input, limb_count) + gen_mstore_evmmax_elem(2, y_input, limb_count) + x2 = (mod - 1) >> 63 + y2 = (mod - 1) >> 63 + store_inputs2 = gen_mstore_evmmax_elem(3, x_input, limb_count) + gen_mstore_evmmax_elem(4, y_input, limb_count) - bench_start = setmod + store_inputs + bench_start = setmod + store_inputs + store_inputs2 loop_body = "" empty_bench_len = int(len(gen_loop().format(bench_start, "", gen_push_int(258))) / 2) @@ -219,7 +222,11 @@ def gen_loop() -> str: def gen_push3_pop_loop_benchmark(count: int) -> str: loop_body = "" for i in range(count): - loop_body += gen_push_literal(gen_encode_evmmax_bytes(1, 2, 3)) + if i % 2 == 0: + loop_body += gen_push_literal(gen_encode_evmmax_bytes(1, 2, 5)) + else: + loop_body += gen_push_literal(gen_encode_evmmax_bytes(3, 4, 5)) + loop_body += EVM_OPS["POP"] return gen_loop().format("", loop_body, gen_push_int(33)) @@ -249,11 +256,11 @@ def bench_geth_evmmax(arith_op_name: str, limb_count: int) -> (int, int): return bench_geth(bench_code), evmmax_op_count - def default_run(): - LOOP_ITERATIONS = 255 # TODO check this + LOOP_ITERATIONS = 255 - for arith_op_name in ["MULMONTMAX"]: #["ADDMODMAX", "SUBMODMAX", "MULMONTMAX"]: + print("op name, limb count, estimated runtime (ns)") + for arith_op_name in ["ADDMODMAX", "SUBMODMAX", "MULMONTMAX"]: for limb_count in range(1,12): evmmax_bench_time, evmmax_op_count = bench_geth_evmmax(arith_op_name, limb_count) @@ -261,8 +268,9 @@ def default_run(): setmod_est_time = 0 # TODO est_time = math.ceil((evmmax_bench_time - push3_pop_bench_time - setmod_est_time) / (evmmax_op_count * LOOP_ITERATIONS)) - print("{} - {} limbs - {} ns/op".format(arith_op_name, limb_count, est_time)) - print() + #print("{} - {} limbs - {} ns/op".format(arith_op_name, limb_count, est_time)) + print("{},{},{}".format(arith_op_name, limb_count, est_time)) + #print() if __name__ == "__main__": if len(sys.argv) == 1: From 12bb7241c3842b1e2331ab5e6f62d70942e34802 Mon Sep 17 00:00:00 2001 From: Jared Wasinger Date: Sun, 7 Aug 2022 18:43:28 -0400 Subject: [PATCH 11/12] update --- evmmax_generator/generate.py | 38 ++++++++++++++++++++++++++++-------- evmmax_generator/go-ethereum | 1 - 2 files changed, 30 insertions(+), 9 deletions(-) delete mode 160000 evmmax_generator/go-ethereum diff --git a/evmmax_generator/generate.py b/evmmax_generator/generate.py index c6c1ed8..7478a1c 100644 --- a/evmmax_generator/generate.py +++ b/evmmax_generator/generate.py @@ -234,7 +234,11 @@ def gen_push3_pop_loop_benchmark(count: int) -> str: # bench some evm bytecode and return the runtime in ns def bench_geth(code: str) -> int: - geth_exec = os.path.join(os.getcwd(), "go-ethereum/build/bin/evm") + geth_path = "go-ethereum/build/bin/evm" + if os.getenv('GETH_EVM') != None: + geth_path = os.getenv('GETH_EVM') + + geth_exec = os.path.join(os.getcwd(), geth_path) geth_cmd = "{} --code {} --bench run".format(geth_exec, code) result = subprocess.run(geth_cmd.split(' '), stdout=subprocess.PIPE, stderr=subprocess.PIPE) if result.returncode != 0: @@ -245,23 +249,37 @@ def bench_geth(code: str) -> int: if exec_time.endswith("ms"): exec_time = int(float(exec_time[:-2]) * 1000000) elif exec_time.endswith("s"): + import pdb; pdb.set_trace() exec_time = int(float(exec_time[:-1]) * 1000000 * 1000) else: raise Exception("unknown timestamp ending: {}".format(exec_time)) return exec_time +LOOP_ITERATIONS = 255 + def bench_geth_evmmax(arith_op_name: str, limb_count: int) -> (int, int): bench_code, evmmax_op_count = gen_arith_loop_benchmark(arith_op_name, limb_count) return bench_geth(bench_code), evmmax_op_count +def bench_run(benches): + for op_name, limb_count_min, limb_count_max in benches: + for i in range(limb_count_min, limb_count_max + 1): + evmmax_bench_time, evmmax_op_count = bench_geth_evmmax(op_name, i) + + push3_pop_bench_time = bench_geth(gen_push3_pop_loop_benchmark(evmmax_op_count)) + setmod_est_time = 0 # TODO + + est_time = math.ceil((evmmax_bench_time - push3_pop_bench_time - setmod_est_time) / (evmmax_op_count * LOOP_ITERATIONS)) + #print("{} - {} limbs - {} ns/op".format(arith_op_name, limb_count, est_time)) + print("{},{},{}".format(op_name, limb_count, est_time)) + def default_run(): - LOOP_ITERATIONS = 255 print("op name, limb count, estimated runtime (ns)") - for arith_op_name in ["ADDMODMAX", "SUBMODMAX", "MULMONTMAX"]: - for limb_count in range(1,12): + for arith_op_name in ["MULMONTMAX"]: #["ADDMODMAX", "SUBMODMAX", "MULMONTMAX"]: + for limb_count in range(1, 12): evmmax_bench_time, evmmax_op_count = bench_geth_evmmax(arith_op_name, limb_count) push3_pop_bench_time = bench_geth(gen_push3_pop_loop_benchmark(evmmax_op_count)) @@ -281,12 +299,16 @@ def default_run(): raise Exception("unknown op") limb_count = int(sys.argv[2]) - if limb_count < 0 or limb_count > 11: - raise Exception("must choose limb count between 1 and 11") + if limb_count < 0 or limb_count > 12: + raise Exception("must choose limb count between 1 and 12") - if sys.argv[3] == "dumpgethcmd": + if len(sys.argv) == 4: + if sys.argv[3] == "dumpgethcmd": + bench_code, evmmax_op_count = gen_arith_loop_benchmark(op, limb_count) + print(bench_code) + else: bench_code, evmmax_op_count = gen_arith_loop_benchmark(op, limb_count) - print(bench_code) + bench_run([(op, limb_count, limb_count)]) else: print("too many args") diff --git a/evmmax_generator/go-ethereum b/evmmax_generator/go-ethereum deleted file mode 160000 index f0eb900..0000000 --- a/evmmax_generator/go-ethereum +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f0eb900ae037c696c8d5b69bfe04a3c9f54e480f From ddfa106127c44ac13e0f19817b29a34f0e366053 Mon Sep 17 00:00:00 2001 From: Jared Wasinger Date: Mon, 8 Aug 2022 19:02:45 -0400 Subject: [PATCH 12/12] fix --- evmmax_generator/generate.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/evmmax_generator/generate.py b/evmmax_generator/generate.py index 7478a1c..829c4f9 100644 --- a/evmmax_generator/generate.py +++ b/evmmax_generator/generate.py @@ -276,9 +276,8 @@ def bench_run(benches): print("{},{},{}".format(op_name, limb_count, est_time)) def default_run(): - - print("op name, limb count, estimated runtime (ns)") - for arith_op_name in ["MULMONTMAX"]: #["ADDMODMAX", "SUBMODMAX", "MULMONTMAX"]: + #print("op name, limb count, estimated runtime (ns)") + for arith_op_name in ["ADDMODMAX", "SUBMODMAX", "MULMONTMAX"]: for limb_count in range(1, 12): evmmax_bench_time, evmmax_op_count = bench_geth_evmmax(arith_op_name, limb_count)