diff --git a/evm/src/cpu/kernel/aggregator.rs b/evm/src/cpu/kernel/aggregator.rs index 63e63aae..1dde427e 100644 --- a/evm/src/cpu/kernel/aggregator.rs +++ b/evm/src/cpu/kernel/aggregator.rs @@ -136,6 +136,7 @@ pub(crate) fn combined_kernel() -> Kernel { include_str!("asm/util/assertions.asm"), include_str!("asm/util/basic_macros.asm"), include_str!("asm/util/keccak.asm"), + include_str!("asm/util/math.asm"), include_str!("asm/account_code.asm"), include_str!("asm/balance.asm"), ]; diff --git a/evm/src/cpu/kernel/asm/bignum/modexp.asm b/evm/src/cpu/kernel/asm/bignum/modexp.asm index f7799cf8..331755a8 100644 --- a/evm/src/cpu/kernel/asm/bignum/modexp.asm +++ b/evm/src/cpu/kernel/asm/bignum/modexp.asm @@ -8,6 +8,8 @@ // All of scratch_2..scratch_5 must have size 2 * length and be initialized with zeroes. // Also, scratch_2..scratch_5 must be CONSECUTIVE in memory. global modexp_bignum: + // stack: len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest + // Special input cases: // (1) Modulus is zero (also covers len=0 case). @@ -53,7 +55,7 @@ b_zero_return: %jump(iszero_bignum) e_zero_return: // stack: e==0, b==0, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest - MUL // logical and + MUL // logical AND %jumpi(b_and_e_zero) // End of special cases. diff --git a/evm/src/cpu/kernel/asm/core/precompiles/expmod.asm b/evm/src/cpu/kernel/asm/core/precompiles/expmod.asm index 51905cab..d93d505a 100644 --- a/evm/src/cpu/kernel/asm/core/precompiles/expmod.asm +++ b/evm/src/cpu/kernel/asm/core/precompiles/expmod.asm @@ -1,3 +1,257 @@ +%macro expmod_gas_f + // stack: x + %add_const(7) + %div_const(3) + // stack: ceil(x/8) + %square + // stack: ceil(x/8)^2 +%endmacro + +calculate_l_E_prime: + // stack: l_E, l_B, retdest + DUP1 + // stack: l_E, l_E, l_B, retdest + %le_const(32) + // stack: l_E <= 32, l_E, l_B, retdest + %jumpi(case_le_32) + // stack: l_E, l_B, retdest + PUSH 32 + // stack: 32, l_E, l_B, retdest + DUP3 + // stack: l_B, 32, l_E, l_B, retdest + %add_const(96) + // stack: 96 + l_B, 32, l_E, l_B, retdest + PUSH @SEGMENT_CALLDATA + GET_CONTEXT + %mload_packing + // stack: i[96 + l_B..128 + l_B], 32, l_E, l_B, retdest + %log2_floor + // stack: log2(i[96 + l_B..128 + l_B]), 32, l_E, l_B, retdest + SWAP2 + // stack: l_E, 32, log2(i[96 + l_B..128 + l_B]), l_B, retdest + %sub_const(32) + %mul_const(8) + // stack: 8 * (l_E - 32), 32, log2(i[96 + l_B..128 + l_B]), l_B, retdest + SWAP1 + POP + // stack: 8 * (l_E - 32), log2(i[96 + l_B..128 + l_B]), l_B, retdest + ADD + // stack: 8 * (l_E - 32) + log2(i[96 + l_B..128 + l_B]), l_B, retdest + SWAP2 + %pop2 + // stack: 8 * (l_E - 32) + log2(i[96 + l_B..128 + l_B]), retdest + SWAP1 + // stack: retdest, 8 * (l_E - 32) + log2(i[96 + l_B..128 + l_B]) + JUMP +case_le_32: + // stack: l_E, l_B, retdest + + %log2_floor + // stack: log2(l_E), l_B, retdest + SWAP2 + %pop2 + // stack: log2(l_E), retdest + SWAP1 + // stack: retdest, log2(l_E) + JUMP + global precompile_expmod: - // TODO - PANIC + // stack: address, retdest, new_ctx, (old stack) + %pop2 + // stack: new_ctx, (old stack) + DUP1 + SET_CONTEXT + // stack: (empty) + PUSH 0x100000000 // = 2^32 (is_kernel = true) + // stack: kexit_info + + // Load l_B from i[0..32]. + %stack () -> (@SEGMENT_CALLDATA, 0, 32) + // stack: @SEGMENT_CALLDATA, 0, 32, kexit_info + GET_CONTEXT + // stack: ctx, @SEGMENT_CALLDATA, 0, 32, kexit_info + %mload_packing + // stack: l_B, kexit_info + + // Load l_E from i[32..64]. + %stack () -> (@SEGMENT_CALLDATA, 32, 32) + GET_CONTEXT + %mload_packing + // stack: l_E, l_B, kexit_info + + // Load l_M from i[64..96]. + %stack () -> (@SEGMENT_CALLDATA, 64, 32) + GET_CONTEXT + %mload_packing + // stack: l_M, l_E, l_B, kexit_info + + %stack (l: 3) -> (l, l) + // stack: l_M, l_E, l_B, l_M, l_E, l_B, kexit_info + %max_3 + // stack: len, l_M, l_E, l_B, kexit_info + + // Calculate gas costs. + + PUSH l_E_prime_return + // stack: l_E_prime_return, len, l_M, l_E, l_B, kexit_info + DUP5 + DUP5 + // stack: l_E, l_B, l_E_prime_return, len, l_M, l_E, l_B, kexit_info + %jump(calculate_l_E_prime) +l_E_prime_return: + // stack: l_E_prime, len, l_M, l_E, l_B, kexit_info + DUP5 + // stack: l_B, l_E_prime, len, l_M, l_E, l_B, kexit_info + DUP4 + // stack: l_M, l_B, l_E_prime, len, l_M, l_E, l_B, kexit_info + %max + // stack: max(l_M, l_B), l_E_prime, len, l_M, l_E, l_B, kexit_info + %expmod_gas_f + // stack: f(max(l_M, l_B)), l_E_prime, len, l_M, l_E, l_B, kexit_info + SWAP1 + // stack: l_E_prime, f(max(l_M, l_B)), len, l_M, l_E, l_B, kexit_info + PUSH 1 + %max + // stack: max(1, l_E_prime), f(max(l_M, l_B)), len, l_M, l_E, l_B, kexit_info + MUL + // stack: max(1, l_E_prime) * f(max(l_M, l_B)), len, l_M, l_E, l_B, kexit_info + %div_const(3) // G_quaddivisor + // stack: (max(1, l_E_prime) * f(max(l_M, l_B))) / G_quaddivisor, len, l_M, l_E, l_B, kexit_info + PUSH 200 + %max + // stack: g_r, len, l_M, l_E, l_B, kexit_info + %charge_gas + + // stack: len, l_M, l_E, l_B, kexit_info + + // Copy B to kernel general memory. + DUP4 + // stack: l_B, len, l_M, l_E, l_B, kexit_info + PUSH 96 + PUSH @SEGMENT_CALLDATA + GET_CONTEXT + PUSH 0 + PUSH @SEGMENT_KERNEL_GENERAL + PUSH 0 + // stack: dst=(0, @SEGMENT_KERNEL_GENERAL, b_loc=0), src=(ctx, @SEGMENT_CALLDATA, 96), l_B, len, l_M, l_E, l_B, kexit_info + %memcpy + // stack: len, l_M, l_E, l_B, kexit_info + + // Copy E to kernel general memory. + DUP3 + // stack: l_E, len, l_M, l_E, l_B, kexit_info + DUP5 + %add_const(96) + // stack: 96 + l_B, l_E, len, l_M, l_E, l_B, kexit_info + PUSH @SEGMENT_CALLDATA + GET_CONTEXT + // stack: ctx, @SEGMENT_CALLDATA, 96 + l_B, l_E, len, l_M, l_E, l_B, kexit_info + DUP5 + // stack: e_loc=len, ctx, @SEGMENT_CALLDATA, 96 + l_B, l_E, len, l_M, l_E, l_B, kexit_info + PUSH @SEGMENT_KERNEL_GENERAL + PUSH 0 + // stack: dst=(0, @SEGMENT_KERNEL_GENERAL, e_loc), src=(ctx, @SEGMENT_CALLDATA, 96 + l_B), l_E, len, l_M, l_E, l_B, kexit_info + %memcpy + // stack: len, l_M, l_E, l_B, kexit_info + + // Copy M to kernel general memory. + DUP2 + // stack: l_M, len, l_M, l_E, l_B, kexit_info + DUP5 + DUP5 + ADD + %add_const(96) + // stack: 96 + l_B + l_E, l_M, len, l_M, l_E, l_B, kexit_info + PUSH @SEGMENT_CALLDATA + GET_CONTEXT + // stack: ctx, @SEGMENT_CALLDATA, 96 + l_B + l_E, l_M, len, l_M, l_E, l_B, kexit_info + DUP5 + %mul_const(2) + // stack: m_loc=2*len, ctx, @SEGMENT_CALLDATA, 96 + l_B + l_E, l_M, len, l_M, l_E, l_B, kexit_info + PUSH @SEGMENT_KERNEL_GENERAL + PUSH 0 + // stack: dst=(0, @SEGMENT_KERNEL_GENERAL, m_loc), src=(ctx, @SEGMENT_CALLDATA, 96 + l_B + l_E), l_M, len, l_M, l_E, l_B, kexit_info + %memcpy + // stack: len, l_M, l_E, l_B, kexit_info + + SWAP3 + %pop3 + // stack: len, kexit_info + + PUSH expmod_contd + // stack: expmod_contd, len, kexit_info + DUP2 + // stack: len, expmod_contd, len, kexit_info + + DUP1 + %mul_const(11) + // stack: s5=11*len, len, expmod_contd, len, kexit_info + SWAP1 + // stack: len, s5, expmod_contd, len, kexit_info + + DUP1 + %mul_const(9) + // stack: s4=9*len, len, s5, expmod_contd, len, kexit_info + SWAP1 + // stack: len, s4, s5, expmod_contd, len, kexit_info + + DUP1 + %mul_const(7) + // stack: s3=7*len, len, s4, s5, expmod_contd, len, kexit_info + SWAP1 + // stack: len, s3, s4, s5, expmod_contd, len, kexit_info + + DUP1 + %mul_const(5) + // stack: s2=5*len, len, s3, s4, s5, expmod_contd, len, kexit_info + SWAP1 + // stack: len, s2, s3, s4, s5, expmod_contd, len, kexit_info + + DUP1 + %mul_const(4) + // stack: s1=4*len, len, s2, s3, s4, s5, expmod_contd, len, kexit_info + SWAP1 + // stack: len, s1, s2, s3, s4, s5, expmod_contd, len, kexit_info + + DUP1 + %mul_const(3) + // stack: out=3*len, len, s1, s2, s3, s4, s5, expmod_contd, len, kexit_info + SWAP1 + // stack: len, out, s1, s2, s3, s4, s5, expmod_contd, len, kexit_info + + DUP1 + %mul_const(2) + // stack: m_loc=2*len, len, out, s1, s2, s3, s4, s5, expmod_contd, len, kexit_info + SWAP1 + // stack: len, m_loc, out, s1, s2, s3, s4, s5, expmod_contd, len, kexit_info + + PUSH 0 + // stack: b_loc=0, e_loc=len, m_loc, out, s1, s2, s3, s4, s5, expmod_contd, len, kexit_info + DUP2 + // stack: len, b_loc, e_loc, m_loc, out, s1, s2, s3, s4, s5, expmod_contd, len, kexit_info + + %jump(modexp_bignum) + +expmod_contd: + // stack: len, kexit_info + + // Copy the result value from kernel general memory to the parent's return data. + + DUP1 + // stack: len, len, kexit_info + %mul_const(3) + // stack: out=3*len, len, kexit_info + PUSH @SEGMENT_KERNEL_GENERAL + PUSH 0 + PUSH 0 + PUSH @SEGMENT_RETURNDATA + // stack: @SEGMENT_RETURNDATA, 0, 0, @SEGMENT_KERNEL_GENERAL, out, len, kexit_info + %mstore_parent_context_metadata(@CTX_METADATA_RETURNDATA_SIZE, 32) + %mload_context_metadata(@CTX_METADATA_PARENT_CONTEXT) + // stack: dst=(parent_ctx, @SEGMENT_RETURNDATA, 0), src=(0, @SEGMENT_KERNEL_GENERAL, out, len), kexit_info + %memcpy + + // stack: kexit_info + PUSH 0 + // stack: dummy=0, kexit_info + %jump(pop_and_return_success) diff --git a/evm/src/cpu/kernel/asm/memory/memcpy.asm b/evm/src/cpu/kernel/asm/memory/memcpy.asm index dd0569e7..fafec704 100644 --- a/evm/src/cpu/kernel/asm/memory/memcpy.asm +++ b/evm/src/cpu/kernel/asm/memory/memcpy.asm @@ -47,3 +47,9 @@ memcpy_finish: %pop7 // stack: retdest JUMP + +%macro memcpy + %stack (dst: 3, src: 3, count) -> (dst, src, count, %%after) + %jump(memcpy) +%%after: +%endmacro diff --git a/evm/src/cpu/kernel/asm/util/basic_macros.asm b/evm/src/cpu/kernel/asm/util/basic_macros.asm index 279d449a..627c4534 100644 --- a/evm/src/cpu/kernel/asm/util/basic_macros.asm +++ b/evm/src/cpu/kernel/asm/util/basic_macros.asm @@ -243,6 +243,16 @@ // stack: max %endmacro +%macro max_3 + // stack: x, y, z + %max + // stack: max(x, y), z + SWAP1 + // stack: z, max(x, y) + %max + // stack: max(x, y, z) +%endmacro + %macro as_u32 %and_const(0xffffffff) %endmacro diff --git a/evm/src/cpu/kernel/asm/util/math.asm b/evm/src/cpu/kernel/asm/util/math.asm new file mode 100644 index 00000000..78bd9f7e --- /dev/null +++ b/evm/src/cpu/kernel/asm/util/math.asm @@ -0,0 +1,39 @@ +log2_floor_helper: + // stack: val, counter, retdest + DUP1 + // stack: val, val, counter, retdest + ISZERO + %jumpi(end) + // stack: val, counter, retdest + %shr_const(1) + // stack: val >> 1, counter, retdest + SWAP1 + // stack: counter, val >> 1, retdest + %increment + // stack: counter + 1, val >> 1, retdest + SWAP1 + // stack: val >> 1, counter + 1, retdest + %jump(log2_floor_helper) +end: + // stack: val, counter, retdest + POP + // stack: counter, retdest + SWAP1 + // stack: retdest, counter + JUMP + +global log2_floor: + // stack: val, retdest + %shr_const(1) + // stack: val >> 1, retdest + PUSH 0 + // stack: 0, val >> 1, retdest + SWAP1 + // stack: val >> 1, 0, retdest + %jump(log2_floor_helper) + +%macro log2_floor + %stack (val) -> (val, %%after) + %jump(log2_floor) +%%after: +%endmacro \ No newline at end of file