diff --git a/evm/src/cpu/kernel/asm/bignum/add.asm b/evm/src/cpu/kernel/asm/bignum/add.asm index c9070dd1..4433ab22 100644 --- a/evm/src/cpu/kernel/asm/bignum/add.asm +++ b/evm/src/cpu/kernel/asm/bignum/add.asm @@ -9,49 +9,55 @@ global add_bignum: ISZERO %jumpi(len_zero) // stack: len, a_start_loc, b_start_loc, retdest + %build_current_general_address_no_offset PUSH 0 - // stack: carry=0, i=len, a_cur_loc=a_start_loc, b_cur_loc=b_start_loc, retdest + // stack: carry=0, base_addr, i=len, a_cur_loc=a_start_loc, b_cur_loc=b_start_loc, retdest add_loop: - // stack: carry, i, a_cur_loc, b_cur_loc, retdest - DUP4 - %mload_current_general - // stack: b[cur], carry, i, a_cur_loc, b_cur_loc, retdest - DUP4 - %mload_current_general - // stack: a[cur], b[cur], carry, i, a_cur_loc, b_cur_loc, retdest - ADD - ADD - // stack: a[cur] + b[cur] + carry, i, a_cur_loc, b_cur_loc, retdest - DUP1 - // stack: a[cur] + b[cur] + carry, a[cur] + b[cur] + carry, i, a_cur_loc, b_cur_loc, retdest - %shr_const(128) - // stack: (a[cur] + b[cur] + carry) // 2^128, a[cur] + b[cur] + carry, i, a_cur_loc, b_cur_loc, retdest - SWAP1 - // stack: a[cur] + b[cur] + carry, (a[cur] + b[cur] + carry) // 2^128, i, a_cur_loc, b_cur_loc, retdest - %mod_const(0x100000000000000000000000000000000) - // stack: c[cur] = (a[cur] + b[cur] + carry) % 2^128, carry_new = (a[cur] + b[cur] + carry) // 2^128, i, a_cur_loc, b_cur_loc, retdest - DUP4 - // stack: a_cur_loc, c[cur], carry_new, i, a_cur_loc, b_cur_loc, retdest - %mstore_current_general - // stack: carry_new, i, a_cur_loc, b_cur_loc, retdest - SWAP2 - %increment - SWAP2 - // stack: carry_new, i, a_cur_loc + 1, b_cur_loc, retdest - SWAP3 - %increment - SWAP3 - // stack: carry_new, i, a_cur_loc + 1, b_cur_loc + 1, retdest - SWAP1 - %decrement - SWAP1 - // stack: carry_new, i - 1, a_cur_loc + 1, b_cur_loc + 1, retdest + // stack: carry, base_addr, i, a_cur_loc, b_cur_loc, retdest DUP2 - // stack: i - 1, carry_new, i - 1, a_cur_loc + 1, b_cur_loc + 1, retdest + // stack: base_addr, carry, base_addr, i, a_cur_loc, b_cur_loc, retdest + DUP6 ADD // base_addr + b_cur_loc + MLOAD_GENERAL + // stack: b[cur], carry, base_addr, i, a_cur_loc, b_cur_loc, retdest + DUP3 + DUP6 ADD // base_addr + a_cur_loc + MLOAD_GENERAL + // stack: a[cur], b[cur], carry, base_addr, i, a_cur_loc, b_cur_loc, retdest + ADD + ADD + // stack: a[cur] + b[cur] + carry, base_addr, i, a_cur_loc, b_cur_loc, retdest + DUP1 + // stack: a[cur] + b[cur] + carry, a[cur] + b[cur] + carry, base_addr, i, a_cur_loc, b_cur_loc, retdest + %shr_const(128) + // stack: (a[cur] + b[cur] + carry) // 2^128, a[cur] + b[cur] + carry, base_addr, i, a_cur_loc, b_cur_loc, retdest + SWAP1 + // stack: a[cur] + b[cur] + carry, (a[cur] + b[cur] + carry) // 2^128, base_addr, i, a_cur_loc, b_cur_loc, retdest + %mod_const(0x100000000000000000000000000000000) + // stack: c[cur] = (a[cur] + b[cur] + carry) % 2^128, carry_new = (a[cur] + b[cur] + carry) // 2^128, base_addr, i, a_cur_loc, b_cur_loc, retdest + DUP3 + DUP6 + ADD // base_addr + a_cur_loc + // stack: a_cur_addr, c[cur], carry_new, base_addr, i, a_cur_loc, b_cur_loc, retdest + %swap_mstore + // stack: carry_new, base_addr, i, a_cur_loc, b_cur_loc, retdest + SWAP3 + %increment + SWAP3 + // stack: carry_new, base_addr, i, a_cur_loc + 1, b_cur_loc, retdest + SWAP4 + %increment + SWAP4 + // stack: carry_new, base_addr, i, a_cur_loc + 1, b_cur_loc + 1, retdest + SWAP2 + %decrement + SWAP2 + // stack: carry_new, base_addr, i - 1, a_cur_loc + 1, b_cur_loc + 1, retdest + DUP3 + // stack: i - 1, carry_new, base_addr, i - 1, a_cur_loc + 1, b_cur_loc + 1, retdest %jumpi(add_loop) add_end: - // stack: carry_new, i - 1, a_cur_loc + 1, b_cur_loc + 1, retdest - %stack (c, i, a, b) -> (c) + // stack: carry_new, base_addr, i - 1, a_cur_loc + 1, b_cur_loc + 1, retdest + %stack (c, addr, i, a, b) -> (c) // stack: carry_new, retdest SWAP1 // stack: retdest, carry_new diff --git a/evm/src/cpu/kernel/asm/bignum/addmul.asm b/evm/src/cpu/kernel/asm/bignum/addmul.asm index 13e59e6d..9cdf904e 100644 --- a/evm/src/cpu/kernel/asm/bignum/addmul.asm +++ b/evm/src/cpu/kernel/asm/bignum/addmul.asm @@ -8,95 +8,99 @@ global addmul_bignum: // stack: len, len, a_start_loc, b_start_loc, val, retdest ISZERO %jumpi(len_zero) + %build_current_general_address_no_offset PUSH 0 - // stack: carry_limb=0, i=len, a_cur_loc=a_start_loc, b_cur_loc=b_start_loc, val, retdest + // stack: carry_limb=0, base_addr, i=len, a_cur_loc=a_start_loc, b_cur_loc=b_start_loc, val, retdest addmul_loop: - // stack: carry_limb, i, a_cur_loc, b_cur_loc, val, retdest - DUP4 - // stack: b_cur_loc, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest - %mload_current_general - // stack: b[cur], carry_limb, i, a_cur_loc, b_cur_loc, val, retdest - DUP6 - // stack: val, b[cur], carry_limb, i, a_cur_loc, b_cur_loc, val, retdest + // stack: carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest + DUP2 + DUP6 ADD // base_addr + b_cur_loc + // stack: b_cur_addr, carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest + MLOAD_GENERAL + // stack: b[cur], carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest + DUP7 + // stack: val, b[cur], carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest MUL - // stack: val * b[cur], carry_limb, i, a_cur_loc, b_cur_loc, val, retdest + // stack: val * b[cur], carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest DUP1 - // stack: val * b[cur], val * b[cur], carry_limb, i, a_cur_loc, b_cur_loc, val, retdest + // stack: val * b[cur], val * b[cur], carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest %shr_const(128) - // stack: (val * b[cur]) // 2^128, val * b[cur], carry_limb, i, a_cur_loc, b_cur_loc, val, retdest + // stack: (val * b[cur]) // 2^128, val * b[cur], carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest SWAP1 - // stack: val * b[cur], (val * b[cur]) // 2^128, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest + // stack: val * b[cur], (val * b[cur]) // 2^128, carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest %shl_const(128) %shr_const(128) - // stack: prod_lo = val * b[cur] % 2^128, prod_hi = (val * b[cur]) // 2^128, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest - DUP5 - // stack: a_cur_loc, prod_lo, prod_hi, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest - %mload_current_general - // stack: a[cur], prod_lo, prod_hi, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest + // stack: prod_lo = val * b[cur] % 2^128, prod_hi = (val * b[cur]) // 2^128, carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest + DUP4 + DUP7 ADD // base_addr + a_cur_loc + // stack: a_cur_addr, prod_lo, prod_hi, carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest + MLOAD_GENERAL + // stack: a[cur], prod_lo, prod_hi, carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest DUP1 - // stack: a[cur], a[cur], prod_lo, prod_hi, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest + // stack: a[cur], a[cur], prod_lo, prod_hi, carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest SWAP2 - // stack: prod_lo, a[cur], a[cur], prod_hi, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest + // stack: prod_lo, a[cur], a[cur], prod_hi, carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest ADD %shl_const(128) %shr_const(128) - // stack: prod_lo' = (prod_lo + a[cur]) % 2^128, a[cur], prod_hi, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest + // stack: prod_lo' = (prod_lo + a[cur]) % 2^128, a[cur], prod_hi, carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest DUP1 - // stack: prod_lo', prod_lo', a[cur], prod_hi, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest + // stack: prod_lo', prod_lo', a[cur], prod_hi, carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest SWAP2 - // stack: a[cur], prod_lo', prod_lo', prod_hi, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest + // stack: a[cur], prod_lo', prod_lo', prod_hi, carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest GT - // stack: prod_lo_carry_limb = a[cur] > prod_lo', prod_lo', prod_hi, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest + // stack: prod_lo_carry_limb = a[cur] > prod_lo', prod_lo', prod_hi, carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest SWAP1 - // stack: prod_lo', prod_lo_carry_limb, prod_hi, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest + // stack: prod_lo', prod_lo_carry_limb, prod_hi, carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest SWAP2 - // stack: prod_hi, prod_lo_carry_limb, prod_lo', carry_limb, i, a_cur_loc, b_cur_loc, val, retdest + // stack: prod_hi, prod_lo_carry_limb, prod_lo', carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest ADD - // stack: prod_hi' = prod_hi + prod_lo_carry_limb, prod_lo', carry_limb, i, a_cur_loc, b_cur_loc, val, retdest + // stack: prod_hi' = prod_hi + prod_lo_carry_limb, prod_lo', carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest DUP3 - // stack: carry_limb, prod_hi', prod_lo', carry_limb, i, a_cur_loc, b_cur_loc, val, retdest + // stack: carry_limb, prod_hi', prod_lo', carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest DUP3 - // stack: prod_lo', carry_limb, prod_hi', prod_lo', carry_limb, i, a_cur_loc, b_cur_loc, val, retdest + // stack: prod_lo', carry_limb, prod_hi', prod_lo', carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest ADD %shl_const(128) %shr_const(128) - // stack: to_write = (prod_lo' + carry_limb) % 2^128, prod_hi', prod_lo', carry_limb, i, a_cur_loc, b_cur_loc, val, retdest + // stack: to_write = (prod_lo' + carry_limb) % 2^128, prod_hi', prod_lo', carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest SWAP2 - // stack: prod_lo', prod_hi', to_write, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest + // stack: prod_lo', prod_hi', to_write, carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest DUP3 - // stack: to_write, prod_lo', prod_hi', to_write, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest + // stack: to_write, prod_lo', prod_hi', to_write, carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest LT // stack: carry_limb_new = to_write < prod_lo', prod_hi', to_write, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest %stack (vals: 3, c) -> (vals) - // stack: carry_limb_new, prod_hi', to_write, i, a_cur_loc, b_cur_loc, val, retdest + // stack: carry_limb_new, prod_hi', to_write, addr, i, a_cur_loc, b_cur_loc, val, retdest ADD - // stack: carry_limb = carry_limb_new' + prod_hi', to_write, i, a_cur_loc, b_cur_loc, val, retdest + // stack: carry_limb = carry_limb_new' + prod_hi', to_write, addr, i, a_cur_loc, b_cur_loc, val, retdest SWAP1 - // stack: to_write, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest - DUP4 - // stack: a_cur_loc, to_write, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest - %mstore_current_general - // stack: carry_limb, i, a_cur_loc, b_cur_loc, val, retdest - SWAP1 - // stack: i, carry_limb, a_cur_loc, b_cur_loc, val, retdest - %decrement - // stack: i-1, carry_limb, a_cur_loc, b_cur_loc, val, retdest + // stack: to_write, carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest + DUP3 + DUP6 ADD // base_addr + a_cur_loc + // stack: a_cur_addr, to_write, carry_limb, addr, i, a_cur_loc, b_cur_loc, val, retdest + %swap_mstore + // stack: carry_limb, base_addr, i, a_cur_loc, b_cur_loc, val, retdest SWAP2 - // stack: a_cur_loc, carry_limb, i-1, b_cur_loc, val, retdest - %increment - // stack: a_cur_loc+1, carry_limb, i-1, b_cur_loc, val, retdest + // stack: i, base_addr, carry_limb, a_cur_loc, b_cur_loc, val, retdest + %decrement + // stack: i-1, base_addr, carry_limb, a_cur_loc, b_cur_loc, val, retdest SWAP3 - // stack: b_cur_loc, carry_limb, i-1, a_cur_loc+1, val, retdest + // stack: a_cur_loc, base_addr, carry_limb, i-1, b_cur_loc, val, retdest %increment - // stack: b_cur_loc+1, carry_limb, i-1, a_cur_loc+1, val, retdest - %stack (b, c, i, a) -> (c, i, a, b) - // stack: carry_limb, i-1, a_cur_loc+1, b_cur_loc+1, val, retdest - DUP2 - // stack: i-1, carry_limb, i-1, a_cur_loc+1, b_cur_loc+1, val, retdest + // stack: a_cur_loc+1, base_addr, carry_limb, i-1, b_cur_loc, val, retdest + SWAP4 + // stack: b_cur_loc, base_addr, carry_limb, i-1, a_cur_loc+1, val, retdest + %increment + // stack: b_cur_loc+1, base_addr, carry_limb, i-1, a_cur_loc+1, val, retdest + %stack (b, addr, c, i, a) -> (c, addr, i, a, b) + // stack: carry_limb, base_addr, i-1, a_cur_loc+1, b_cur_loc+1, val, retdest + DUP3 + // stack: i-1, carry_limb, base_addr, i-1, a_cur_loc+1, b_cur_loc+1, val, retdest %jumpi(addmul_loop) addmul_end: - // stack: carry_limb_new, i-1, a_cur_loc+1, b_cur_loc+1, val, retdest - %stack (c, i, a, b, v) -> (c) + // stack: carry_limb_new, base_addr, i-1, a_cur_loc+1, b_cur_loc+1, val, retdest + %stack (c, addr, i, a, b, v) -> (c) // stack: carry_limb_new, retdest SWAP1 // stack: retdest, carry_limb_new diff --git a/evm/src/cpu/kernel/asm/bignum/cmp.asm b/evm/src/cpu/kernel/asm/bignum/cmp.asm index cf6b547f..c2768754 100644 --- a/evm/src/cpu/kernel/asm/bignum/cmp.asm +++ b/evm/src/cpu/kernel/asm/bignum/cmp.asm @@ -5,82 +5,87 @@ // Returns 1 if a > b, 0 if a == b, and -1 (that is, 2^256 - 1) if a < b. global cmp_bignum: // stack: len, a_start_loc, b_start_loc, retdest - DUP1 - // stack: len, len, a_start_loc, b_start_loc, retdest + %build_current_general_address_no_offset + // stack: base_addr, len, a_start_loc, b_start_loc, retdest + DUP2 + // stack: len, base_addr, len, a_start_loc, b_start_loc, retdest ISZERO - %jumpi(equal) - // stack: len, a_start_loc, b_start_loc, retdest - SWAP1 - // stack: a_start_loc, len, b_start_loc, retdest - PUSH 1 - DUP3 - SUB - // stack: len-1, a_start_loc, len, b_start_loc, retdest - ADD - // stack: a_end_loc, len, b_start_loc, retdest + %jumpi(equal) // len and base_addr are swapped, but they will be popped anyway + // stack: base_addr, len, a_start_loc, b_start_loc, retdest SWAP2 - // stack: b_start_loc, len, a_end_loc, retdest + // stack: a_start_loc, len, base_addr, b_start_loc, retdest PUSH 1 DUP3 SUB - // stack: len-1, b_start_loc, len, a_end_loc, retdest + // stack: len-1, a_start_loc, len, base_addr, b_start_loc, retdest ADD - // stack: b_end_loc, len, a_end_loc, retdest - %stack (b, l, a) -> (l, a, b) - // stack: len, a_end_loc, b_end_loc, retdest + // stack: a_end_loc, len, base_addr, b_start_loc, retdest + SWAP3 + // stack: b_start_loc, len, base_addr, a_end_loc, retdest + PUSH 1 + DUP3 + SUB + // stack: len-1, b_start_loc, len, base_addr, a_end_loc, retdest + ADD + // stack: b_end_loc, len, base_addr, a_end_loc, retdest + + %stack (b, l, addr, a) -> (l, addr, a, b) + // stack: len, base_addr, a_end_loc, b_end_loc, retdest %decrement ge_loop: - // stack: i, a_i_loc, b_i_loc, retdest - DUP3 - DUP3 - // stack: a_i_loc, b_i_loc, i, a_i_loc, b_i_loc, retdest - %mload_current_general - SWAP1 - %mload_current_general - SWAP1 - // stack: a[i], b[i], i, a_i_loc, b_i_loc, retdest + // stack: i, base_addr, a_i_loc, b_i_loc, retdest + DUP4 + // stack: b_i_loc, i, base_addr, a_i_loc, b_i_loc, retdest + DUP3 ADD // b_i_addr + MLOAD_GENERAL + // stack: b[i], i, base_addr, a_i_loc, b_i_loc, retdest + DUP4 + // stack: a_i_loc, b[i], i, base_addr, a_i_loc, b_i_loc, retdest + DUP4 ADD // a_i_addr + MLOAD_GENERAL + // stack: a[i], b[i], i, base_addr, a_i_loc, b_i_loc, retdest %stack (vals: 2) -> (vals, vals) GT %jumpi(greater) - // stack: a[i], b[i], i, a_i_loc, b_i_loc, retdest + // stack: a[i], b[i], i, base_addr, a_i_loc, b_i_loc, retdest LT %jumpi(less) - // stack: i, a_i_loc, b_i_loc, retdest + // stack: i, base_addr, a_i_loc, b_i_loc, retdest DUP1 ISZERO %jumpi(equal) %decrement - // stack: i-1, a_i_loc, b_i_loc, retdest - SWAP1 - // stack: a_i_loc, i-1, b_i_loc, retdest - %decrement - // stack: a_i_loc_new, i-1, b_i_loc, retdest + // stack: i-1, base_addr, a_i_loc, b_i_loc, retdest SWAP2 - // stack: b_i_loc, i-1, a_i_loc_new, retdest + // stack: a_i_loc, base_addr, i-1, b_i_loc, retdest %decrement - // stack: b_i_loc_new, i-1, a_i_loc_new, retdest - %stack (b, i, a) -> (i, a, b) - // stack: i-1, a_i_loc_new, b_i_loc_new, retdest + // stack: a_i_loc_new, base_addr, i-1, b_i_loc, retdest + SWAP3 + // stack: b_i_loc, base_addr, i-1, a_i_loc_new, retdest + %decrement + // stack: b_i_loc_new, base_addr, i-1, a_i_loc_new, retdest + %stack (b, addr, i, a) -> (i, addr, a, b) + // stack: i-1, base_addr, a_i_loc_new, b_i_loc_new, retdest %jump(ge_loop) equal: - // stack: i, a_i_loc, b_i_loc, retdest - %pop3 + // stack: i, base_addr, a_i_loc, b_i_loc, retdest + %pop4 // stack: retdest PUSH 0 // stack: 0, retdest SWAP1 JUMP greater: - // stack: a[i], b[i], i, a_i_loc, b_i_loc, retdest - %pop5 + // stack: a[i], b[i], i, base_addr, a_i_loc, b_i_loc, retdest + %pop6 // stack: retdest PUSH 1 // stack: 1, retdest SWAP1 JUMP less: - // stack: i, a_i_loc, b_i_loc, retdest - %pop3 + // stack: i, base_addr, a_i_loc, b_i_loc, retdest + %pop4 // stack: retdest PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff // stack: -1, retdest diff --git a/evm/src/cpu/kernel/asm/bignum/modmul.asm b/evm/src/cpu/kernel/asm/bignum/modmul.asm index 8b19d3e1..9735f610 100644 --- a/evm/src/cpu/kernel/asm/bignum/modmul.asm +++ b/evm/src/cpu/kernel/asm/bignum/modmul.asm @@ -21,28 +21,32 @@ global modmul_bignum: // STEP 1: // The prover provides x := (a * b) % m, which we store in output_loc. + %build_current_general_address_no_offset + PUSH 0 - // stack: i=0, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest + // stack: i=0, base_addr, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest modmul_remainder_loop: - // stack: i, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest + // stack: i, base_addr, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest PROVER_INPUT(bignum_modmul) - // stack: PI, i, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest - DUP7 + // stack: PI, i, base_addr, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest + DUP8 DUP3 ADD - // stack: out_loc[i], PI, i, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest - %mstore_current_general - // stack: i, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest + // stack: out_loc[i], PI, i, base_addr, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest + DUP4 ADD // out_addr_i + %swap_mstore + // stack: i, base_addr, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest %increment + DUP3 DUP2 - DUP2 - // stack: i+1, len, i+1, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest + // stack: i+1, len, i+1, base_addr, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest SUB // functions as NEQ - // stack: i+1!=len, i+1, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest + // stack: i+1!=len, i+1, base_addr, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest %jumpi(modmul_remainder_loop) // end of modmul_remainder_loop - // stack: i, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest - POP + // stack: i, base_addr, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest + %pop2 + // stack: len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest // stack: len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest @@ -69,28 +73,32 @@ modmul_return_1: // stack: len, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest %mul_const(2) // stack: 2*len, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest + + %build_current_general_address_no_offset + PUSH 0 - // stack: i=0, 2*len, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest + // stack: i=0, base_addr, 2*len, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest modmul_quotient_loop: - // stack: i, 2*len, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest + // stack: i, base_addr, 2*len, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest PROVER_INPUT(bignum_modmul) - // stack: PI, i, 2*len, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest - DUP9 + // stack: PI, i, base_addr, 2*len, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest + DUP10 DUP3 ADD - // stack: s1[i], PI, i, 2*len, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest - %mstore_current_general - // stack: i, 2*len, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest + // stack: s1[i], PI, i, base_addr, 2*len, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest + DUP4 ADD // s1_addr_i + %swap_mstore + // stack: i, base_addr, 2*len, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest %increment + DUP3 DUP2 - DUP2 - // stack: i+1, 2*len, i+1, 2*len, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest + // stack: i+1, 2*len, i+1, base_addr, 2*len, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest SUB // functions as NEQ - // stack: i+1!=2*len, i+1, 2*len, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest + // stack: i+1!=2*len, i+1, base_addr, 2*len, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest %jumpi(modmul_quotient_loop) // end of modmul_quotient_loop - // stack: i, 2*len, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest - %pop2 + // stack: i, base_addr, 2*len, len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest + %pop3 // stack: len, a_loc, b_loc, m_loc, out_loc, s1, s2, s3, retdest // STEP 4: @@ -130,33 +138,36 @@ modmul_return_4: // STEP 6: // Check that x + k * m = a * b. - // Walk through scratch_2 and scratch_3, checking that they are equal. - // stack: n=len, i=s2, j=s3, retdest + %build_current_general_address_no_offset + // stack: base_addr, n=len, i=s2, j=s3, retdest modmul_check_loop: - // stack: n, i, j, retdest - %stack (l, idx: 2) -> (idx, l, idx) - // stack: i, j, n, i, j, retdest - %mload_current_general - SWAP1 - %mload_current_general - SWAP1 - // stack: mem[i], mem[j], n, i, j, retdest + // stack: base_addr, n, i, j, retdest + %stack (addr, l, i, j) -> (j, i, addr, addr, l, i, j) + // stack: j, i, base_addr, base_addr, n, i, j, retdest + DUP3 ADD // addr_j + MLOAD_GENERAL + // stack: mem[j], i, base_addr, base_addr, n, i, j, retdest + SWAP2 + ADD // addr_i + MLOAD_GENERAL + // stack: mem[i], mem[j], base_addr, n, i, j, retdest %assert_eq - // stack: n, i, j, retdest + // stack: base_addr, n, i, j, retdest + SWAP1 %decrement - SWAP1 - %increment + // stack: n-1, base_addr, i, j, retdest SWAP2 %increment - SWAP2 - SWAP1 - // stack: n-1, i+1, j+1, retdest - DUP1 - // stack: n-1, n-1, i+1, j+1, retdest + // stack: i+1, base_addr, n-1, j, retdest + SWAP3 + %increment + // stack: j+1, base_addr, n-1, i+1, retdest + %stack (j, addr, n, i) -> (n, addr, n, i, j) + // stack: n-1, base_addr, n-1, i+1, j+1, retdest %jumpi(modmul_check_loop) // end of modmul_check_loop - // stack: n-1, i+1, j+1, retdest - %pop3 + // stack: base_addr, n-1, i+1, j+1, retdest + %pop4 // stack: retdest JUMP diff --git a/evm/src/cpu/kernel/asm/bignum/mul.asm b/evm/src/cpu/kernel/asm/bignum/mul.asm index ddb3346d..b3269f73 100644 --- a/evm/src/cpu/kernel/asm/bignum/mul.asm +++ b/evm/src/cpu/kernel/asm/bignum/mul.asm @@ -12,49 +12,54 @@ global mul_bignum: // stack: len, len, a_start_loc, b_start_loc, output_loc, retdest ISZERO %jumpi(len_zero) - DUP1 - // stack: n=len, len, a_start_loc, bi=b_start_loc, output_cur=output_loc, retdest + + %build_current_general_address_no_offset + + DUP2 + // stack: n=len, base_addr, len, a_start_loc, bi=b_start_loc, output_cur=output_loc, retdest mul_loop: - // stack: n, len, a_start_loc, bi, output_cur, retdest + // stack: n, base_addr, len, a_start_loc, bi, output_cur, retdest PUSH mul_addmul_return - // stack: mul_addmul_return, n, len, a_start_loc, bi, output_cur, retdest - DUP5 - // stack: bi, mul_addmul_return, n, len, a_start_loc, bi, output_cur, retdest - %mload_current_general - // stack: b[i], mul_addmul_return, n, len, a_start_loc, bi, output_cur, retdest, b - DUP5 - // stack: a_start_loc, b[i], mul_addmul_return, n, len, a_start_loc, bi, output_cur, retdest, b - DUP8 - // stack: output_loc, a_start_loc, b[i], mul_addmul_return, n, len, a_start_loc, bi, output_cur, retdest, b + // stack: mul_addmul_return, n, base_addr, len, a_start_loc, bi, output_cur, retdest DUP6 - // stack: len, output_loc, a_start_loc, b[i], mul_addmul_return, n, len, a_start_loc, bi, output_cur, retdest, b + // stack: bi, mul_addmul_return, n, base_addr, len, a_start_loc, bi, output_cur, retdest + DUP4 ADD // bi_addr + MLOAD_GENERAL + // stack: b[i], mul_addmul_return, n, base_addr, len, a_start_loc, bi, output_cur, retdest + DUP6 + // stack: a_start_loc, b[i], mul_addmul_return, n, base_addr, len, a_start_loc, bi, output_cur, retdest + DUP9 + // stack: output_loc, a_start_loc, b[i], mul_addmul_return, n, base_addr, len, a_start_loc, bi, output_cur, retdest + DUP7 + // stack: len, output_loc, a_start_loc, b[i], mul_addmul_return, n, base_addr, len, a_start_loc, bi, output_cur, retdest %jump(addmul_bignum) mul_addmul_return: - // stack: carry_limb, n, len, a_start_loc, bi, output_cur, retdest - DUP6 - // stack: output_cur, carry_limb, n, len, a_start_loc, bi, output_cur, retdest - DUP4 - // stack: len, output_cur, carry_limb, n, len, a_start_loc, bi, output_cur, retdest + // stack: carry_limb, n, base_addr, len, a_start_loc, bi, output_cur, retdest + DUP7 + // stack: output_cur, carry_limb, n, base_addr, len, a_start_loc, bi, output_cur, retdest + DUP5 + // stack: len, output_cur, carry_limb, n, base_addr, len, a_start_loc, bi, output_cur, retdest ADD - // stack: output_cur + len, carry_limb, n, len, a_start_loc, bi, output_cur, retdest - %mstore_current_general - // stack: n, len, a_start_loc, bi, output_cur, retdest + // stack: output_cur + len, carry_limb, n, base_addr, len, a_start_loc, bi, output_cur, retdest + DUP4 ADD + %swap_mstore + // stack: n, base_addr, len, a_start_loc, bi, output_cur, retdest %decrement - // stack: n-1, len, a_start_loc, bi, output_cur, retdest - SWAP3 - %increment - SWAP3 - // stack: n-1, len, a_start_loc, bi+1, output_cur, retdest + // stack: n-1, base_addr, len, a_start_loc, bi, output_cur, retdest SWAP4 %increment SWAP4 - // stack: n-1, len, a_start_loc, bi+1, output_cur+1, retdest + // stack: n-1, base_addr, len, a_start_loc, bi+1, output_cur, retdest + SWAP5 + %increment + SWAP5 + // stack: n-1, base_addr, len, a_start_loc, bi+1, output_cur+1, retdest DUP1 - // stack: n-1, n-1, len, a_start_loc, bi+1, output_cur+1, retdest + // stack: n-1, n-1, base_addr, len, a_start_loc, bi+1, output_cur+1, retdest %jumpi(mul_loop) mul_end: - // stack: n-1, len, a_start_loc, bi+1, output_cur+1, retdest - %pop5 + // stack: n-1, base_addr, len, a_start_loc, bi+1, output_cur+1, retdest + %pop6 // stack: retdest JUMP diff --git a/evm/src/cpu/kernel/asm/bignum/shr.asm b/evm/src/cpu/kernel/asm/bignum/shr.asm index 16d8403c..88d08f05 100644 --- a/evm/src/cpu/kernel/asm/bignum/shr.asm +++ b/evm/src/cpu/kernel/asm/bignum/shr.asm @@ -16,48 +16,54 @@ global shr_bignum: // stack: start_loc + len, start_loc, retdest %decrement // stack: end_loc, start_loc, retdest - %stack (e) -> (e, 0) - // stack: i=end_loc, carry=0, start_loc, retdest + + %build_current_general_address_no_offset + + // stack: base_addr, end_loc, start_loc, retdest + %stack (addr, e) -> (e, addr, 0) + // stack: i=end_loc, base_addr, carry=0, start_loc, retdest shr_loop: - // stack: i, carry, start_loc, retdest + // stack: i, base_addr, carry, start_loc, retdest DUP1 - // stack: i, i, carry, start_loc, retdest - %mload_current_general - // stack: a[i], i, carry, start_loc, retdest + // stack: i, i, base_addr, carry, start_loc, retdest + DUP3 ADD // addr_i + MLOAD_GENERAL + // stack: a[i], i, base_addr, carry, start_loc, retdest DUP1 - // stack: a[i], a[i], i, carry, start_loc, retdest + // stack: a[i], a[i], i, base_addr, carry, start_loc, retdest %shr_const(1) - // stack: a[i] >> 1, a[i], i, carry, start_loc, retdest + // stack: a[i] >> 1, a[i], i, base_addr, carry, start_loc, retdest SWAP1 - // stack: a[i], a[i] >> 1, i, carry, start_loc, retdest + // stack: a[i], a[i] >> 1, i, base_addr, carry, start_loc, retdest %mod_const(2) - // stack: new_carry = a[i] % 2, a[i] >> 1, i, carry, start_loc, retdest - SWAP3 - // stack: carry, a[i] >> 1, i, new_carry, start_loc, retdest + // stack: new_carry = a[i] % 2, a[i] >> 1, i, base_addr, carry, start_loc, retdest + SWAP4 + // stack: carry, a[i] >> 1, i, base_addr, new_carry, start_loc, retdest %shl_const(127) - // stack: carry << 127, a[i] >> 1, i, new_carry, start_loc, retdest + // stack: carry << 127, a[i] >> 1, i, base_addr, new_carry, start_loc, retdest ADD - // stack: carry << 127 | a[i] >> 1, i, new_carry, start_loc, retdest + // stack: carry << 127 | a[i] >> 1, i, base_addr, new_carry, start_loc, retdest DUP2 - // stack: i, carry << 127 | a[i] >> 1, i, new_carry, start_loc, retdest - %mstore_current_general - // stack: i, new_carry, start_loc, retdest + // stack: i, carry << 127 | a[i] >> 1, i, base_addr, new_carry, start_loc, retdest + DUP4 ADD // addr_i + %swap_mstore + // stack: i, base_addr, new_carry, start_loc, retdest PUSH 1 DUP2 SUB - // stack: i-1, i, new_carry, start_loc, retdest + // stack: i-1, i, base_addr, new_carry, start_loc, retdest SWAP1 - // stack: i, i-1, new_carry, start_loc, retdest - DUP4 - // stack: start_loc, i, i-1, new_carry, start_loc, retdest + // stack: i, i-1, base_addr, new_carry, start_loc, retdest + DUP5 + // stack: start_loc, i, i-1, base_addr, new_carry, start_loc, retdest EQ - // stack: i == start_loc, i-1, new_carry, start_loc, retdest + // stack: i == start_loc, i-1, base_addr, new_carry, start_loc, retdest ISZERO - // stack: i != start_loc, i-1, new_carry, start_loc, retdest + // stack: i != start_loc, i-1, base_addr, new_carry, start_loc, retdest %jumpi(shr_loop) shr_end: - // stack: i, new_carry, start_loc, retdest - %pop3 + // stack: i, base_addr, new_carry, start_loc, retdest + %pop4 // stack: retdest JUMP diff --git a/evm/src/cpu/kernel/asm/bignum/util.asm b/evm/src/cpu/kernel/asm/bignum/util.asm index 0385deec..f0a15634 100644 --- a/evm/src/cpu/kernel/asm/bignum/util.asm +++ b/evm/src/cpu/kernel/asm/bignum/util.asm @@ -1,7 +1,7 @@ %macro memcpy_current_general // stack: dst, src, len // DST and SRC are offsets, for the same memory segment - GET_CONTEXT PUSH @SEGMENT_KERNEL_GENERAL %build_address_no_offset + %build_current_general_address_no_offset %stack (addr_no_offset, dst, src, len) -> (addr_no_offset, src, addr_no_offset, dst, len, %%after) ADD // stack: SRC, addr_no_offset, dst, len, %%after @@ -14,7 +14,7 @@ %macro clear_current_general // stack: dst, len - GET_CONTEXT PUSH @SEGMENT_KERNEL_GENERAL %build_address + %build_current_general_address %stack (DST, len) -> (DST, len, %%after) %jump(memset) %%after: diff --git a/evm/src/cpu/kernel/asm/hash/blake2/addresses.asm b/evm/src/cpu/kernel/asm/hash/blake2/addresses.asm index 5beb1dee..3244cfa1 100644 --- a/evm/src/cpu/kernel/asm/hash/blake2/addresses.asm +++ b/evm/src/cpu/kernel/asm/hash/blake2/addresses.asm @@ -2,11 +2,7 @@ // It is ready to be used, i.e. already containing the current context // and SEGMENT_KERNEL_GENERAL. %macro blake2_hash_value_addr - PUSH @SEGMENT_KERNEL_GENERAL - // stack: segment - GET_CONTEXT - // stack: context, segment - %build_address_no_offset + %build_current_general_address_no_offset DUP1 MLOAD_GENERAL // stack: num_blocks, addr diff --git a/evm/src/cpu/kernel/asm/hash/sha2/compression.asm b/evm/src/cpu/kernel/asm/hash/sha2/compression.asm index f25ff302..a9467a00 100644 --- a/evm/src/cpu/kernel/asm/hash/sha2/compression.asm +++ b/evm/src/cpu/kernel/asm/hash/sha2/compression.asm @@ -4,9 +4,7 @@ // stack: num_blocks %mul_const(320) %add_const(2) - PUSH @SEGMENT_KERNEL_GENERAL - GET_CONTEXT - %build_address + %build_current_general_address %endmacro global sha2_compression: diff --git a/evm/src/cpu/kernel/asm/hash/sha2/main.asm b/evm/src/cpu/kernel/asm/hash/sha2/main.asm index 039379f3..53967f8a 100644 --- a/evm/src/cpu/kernel/asm/hash/sha2/main.asm +++ b/evm/src/cpu/kernel/asm/hash/sha2/main.asm @@ -1,8 +1,6 @@ global sha2: // stack: virt, num_bytes, retdest - PUSH @SEGMENT_KERNEL_GENERAL - GET_CONTEXT - %build_address + %build_current_general_address // stack: addr, num_bytes, retdest DUP1 SWAP2 // stack: num_bytes, addr, addr, retdest diff --git a/evm/src/cpu/kernel/asm/hash/sha2/message_schedule.asm b/evm/src/cpu/kernel/asm/hash/sha2/message_schedule.asm index b789a7fb..66fa67a9 100644 --- a/evm/src/cpu/kernel/asm/hash/sha2/message_schedule.asm +++ b/evm/src/cpu/kernel/asm/hash/sha2/message_schedule.asm @@ -3,9 +3,7 @@ // stack: num_blocks %mul_const(64) %add_const(2) - PUSH @SEGMENT_KERNEL_GENERAL - GET_CONTEXT - %build_address + %build_current_general_address %endmacro // Precondition: stack contains address of one message block, followed by output address @@ -188,9 +186,7 @@ global sha2_gen_all_message_schedules: // stack: num_blocks, output_addr, output_addr, retdest PUSH 1 // stack: cur_offset = 1, counter = num_blocks, output_addr, output_addr, retdest - PUSH @SEGMENT_KERNEL_GENERAL - GET_CONTEXT - %build_address + %build_current_general_address // stack: cur_addr, counter, output_addr, output_addr, retdest gen_all_message_schedules_loop: // stack: cur_addr, counter, cur_output_addr, output_addr, retdest diff --git a/evm/src/cpu/kernel/asm/hash/sha2/write_length.asm b/evm/src/cpu/kernel/asm/hash/sha2/write_length.asm index c9a0642f..9c2707b8 100644 --- a/evm/src/cpu/kernel/asm/hash/sha2/write_length.asm +++ b/evm/src/cpu/kernel/asm/hash/sha2/write_length.asm @@ -1,8 +1,6 @@ %macro sha2_write_length // stack: last_addr_offset, length - PUSH @SEGMENT_KERNEL_GENERAL - GET_CONTEXT - %build_address + %build_current_general_address SWAP1 // stack: length, last_addr DUP1 diff --git a/evm/src/cpu/kernel/asm/memory/core.asm b/evm/src/cpu/kernel/asm/memory/core.asm index dad5979f..070e474f 100644 --- a/evm/src/cpu/kernel/asm/memory/core.asm +++ b/evm/src/cpu/kernel/asm/memory/core.asm @@ -127,9 +127,7 @@ // Load a single value from the kernel general memory, in the current context (not the kernel's context). %macro mload_current_general_no_offset // stack: - PUSH @SEGMENT_KERNEL_GENERAL - GET_CONTEXT - %build_address_no_offset + %build_current_general_address_no_offset MLOAD_GENERAL // stack: value %endmacro @@ -137,11 +135,7 @@ // Load a big-endian u32 from kernel general memory in the current context. %macro mload_current_general_u32 // stack: offset - PUSH @SEGMENT_KERNEL_GENERAL - // stack: segment, offset - GET_CONTEXT - // stack: context, segment, offset - %build_address + %build_current_general_address %mload_u32 // stack: value %endmacro @@ -149,11 +143,7 @@ // Load a little-endian u32 from kernel general memory in the current context. %macro mload_current_general_u32_LE // stack: offset - PUSH @SEGMENT_KERNEL_GENERAL - // stack: segment, offset - GET_CONTEXT - // stack: context, segment, offset - %build_address + %build_current_general_address %mload_u32_LE // stack: value %endmacro @@ -161,11 +151,7 @@ // Load a little-endian u64 from kernel general memory in the current context. %macro mload_current_general_u64_LE // stack: offset - PUSH @SEGMENT_KERNEL_GENERAL - // stack: segment, offset - GET_CONTEXT - // stack: context, segment, offset - %build_address + %build_current_general_address %mload_u64_LE // stack: value %endmacro @@ -173,11 +159,7 @@ // Load a u256 from kernel general memory in the current context. %macro mload_current_general_u256 // stack: offset - PUSH @SEGMENT_KERNEL_GENERAL - // stack: segment, offset - GET_CONTEXT - // stack: context, segment, offset - %build_address + %build_current_general_address %mload_u256 // stack: value %endmacro @@ -185,11 +167,7 @@ // Store a single value to kernel general memory in the current context. %macro mstore_current_general // stack: offset, value - PUSH @SEGMENT_KERNEL_GENERAL - // stack: segment, offset, value - GET_CONTEXT - // stack: context, segment, offset, value - %build_address + %build_current_general_address SWAP1 MSTORE_GENERAL // stack: (empty) @@ -198,11 +176,7 @@ // Store a single value to kernel general memory in the current context. %macro mstore_current_general_no_offset // stack: value - PUSH @SEGMENT_KERNEL_GENERAL - // stack: segment, value - GET_CONTEXT - // stack: context, segment, value - %build_address_no_offset + %build_current_general_address_no_offset SWAP1 MSTORE_GENERAL // stack: (empty) @@ -219,11 +193,7 @@ // Store a big-endian u32 to kernel general memory in the current context. %macro mstore_current_general_u32 // stack: offset, value - PUSH @SEGMENT_KERNEL_GENERAL - // stack: segment, offset, value - GET_CONTEXT - // stack: context, segment, offset, value - %build_address + %build_current_general_address %mstore_u32 // stack: (empty) %endmacro diff --git a/evm/src/cpu/kernel/asm/util/basic_macros.asm b/evm/src/cpu/kernel/asm/util/basic_macros.asm index 8753e1ca..78fd34fc 100644 --- a/evm/src/cpu/kernel/asm/util/basic_macros.asm +++ b/evm/src/cpu/kernel/asm/util/basic_macros.asm @@ -440,6 +440,22 @@ // stack: addr %endmacro +%macro build_current_general_address + // stack: offset + PUSH @SEGMENT_KERNEL_GENERAL + GET_CONTEXT + %build_address + // stack: addr +%endmacro + +%macro build_current_general_address_no_offset + // stack: + PUSH @SEGMENT_KERNEL_GENERAL + GET_CONTEXT + %build_address_no_offset + // stack: addr (offset == 0) +%endmacro + %macro build_kernel_address // stack: seg, off ADD diff --git a/evm/src/generation/prover_input.rs b/evm/src/generation/prover_input.rs index f3078239..a6d045d6 100644 --- a/evm/src/generation/prover_input.rs +++ b/evm/src/generation/prover_input.rs @@ -169,10 +169,10 @@ impl GenerationState { // Subsequent calls return one limb at a time, in order (first remainder and then quotient). fn run_bignum_modmul(&mut self) -> Result { if self.bignum_modmul_result_limbs.is_empty() { - let len = stack_peek(self, 1).map(u256_to_usize)??; - let a_start_loc = stack_peek(self, 2).map(u256_to_usize)??; - let b_start_loc = stack_peek(self, 3).map(u256_to_usize)??; - let m_start_loc = stack_peek(self, 4).map(u256_to_usize)??; + let len = stack_peek(self, 2).map(u256_to_usize)??; + let a_start_loc = stack_peek(self, 3).map(u256_to_usize)??; + let b_start_loc = stack_peek(self, 4).map(u256_to_usize)??; + let m_start_loc = stack_peek(self, 5).map(u256_to_usize)??; let (remainder, quotient) = self.bignum_modmul(len, a_start_loc, b_start_loc, m_start_loc);