From fa605d7b221414fae2e8ca8399592c74e2372901 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Fri, 10 Feb 2023 16:31:35 -0800 Subject: [PATCH 01/62] basic bignum --- evm/Cargo.toml | 1 + evm/src/cpu/kernel/aggregator.rs | 7 + evm/src/cpu/kernel/asm/bignum/add.asm | 56 +++++ evm/src/cpu/kernel/asm/bignum/ge.asm | 80 +++++++ evm/src/cpu/kernel/asm/bignum/iszero.asm | 36 +++ evm/src/cpu/kernel/asm/bignum/mul.asm | 202 +++++++++++++++++ evm/src/cpu/kernel/asm/bignum/shr.asm | 56 +++++ evm/src/cpu/kernel/asm/bignum/util.asm | 13 ++ evm/src/cpu/kernel/asm/memory/memset.asm | 38 ++++ evm/src/cpu/kernel/asm/util/basic_macros.asm | 8 + evm/src/cpu/kernel/constants/mod.rs | 14 +- evm/src/cpu/kernel/evm_asm.pest | 2 +- evm/src/cpu/kernel/interpreter.rs | 18 ++ evm/src/cpu/kernel/tests/bignum.rs | 222 +++++++++++++++++++ evm/src/cpu/kernel/tests/mod.rs | 1 + evm/src/keccak/keccak_stark.rs | 2 +- evm/src/util.rs | 38 ++++ plonky2/src/fri/recursive_verifier.rs | 8 +- plonky2/src/gadgets/split_base.rs | 3 +- plonky2/src/gates/random_access.rs | 4 +- plonky2/src/hash/merkle_tree.rs | 4 +- plonky2/src/iop/generator.rs | 3 +- plonky2/src/iop/witness.rs | 6 +- 23 files changed, 799 insertions(+), 23 deletions(-) create mode 100644 evm/src/cpu/kernel/asm/bignum/add.asm create mode 100644 evm/src/cpu/kernel/asm/bignum/ge.asm create mode 100644 evm/src/cpu/kernel/asm/bignum/iszero.asm create mode 100644 evm/src/cpu/kernel/asm/bignum/mul.asm create mode 100644 evm/src/cpu/kernel/asm/bignum/shr.asm create mode 100644 evm/src/cpu/kernel/asm/bignum/util.asm create mode 100644 evm/src/cpu/kernel/asm/memory/memset.asm create mode 100644 evm/src/cpu/kernel/tests/bignum.rs diff --git a/evm/Cargo.toml b/evm/Cargo.toml index d9de1d16..f2fb889d 100644 --- a/evm/Cargo.toml +++ b/evm/Cargo.toml @@ -22,6 +22,7 @@ keccak-hash = "0.10.0" log = "0.4.14" plonky2_maybe_rayon = "0.1.0" num = "0.4.0" +num-bigint = "0.4.3" once_cell = "1.13.0" pest = "2.1.3" pest_derive = "2.1.0" diff --git a/evm/src/cpu/kernel/aggregator.rs b/evm/src/cpu/kernel/aggregator.rs index 1d8f11a0..53787e48 100644 --- a/evm/src/cpu/kernel/aggregator.rs +++ b/evm/src/cpu/kernel/aggregator.rs @@ -11,6 +11,12 @@ pub static KERNEL: Lazy = Lazy::new(combined_kernel); pub(crate) fn combined_kernel() -> Kernel { let files = vec![ + include_str!("asm/bignum/add.asm"), + include_str!("asm/bignum/ge.asm"), + include_str!("asm/bignum/iszero.asm"), + include_str!("asm/bignum/mul.asm"), + include_str!("asm/bignum/shr.asm"), + include_str!("asm/bignum/util.asm"), include_str!("asm/core/bootloader.asm"), include_str!("asm/core/call.asm"), include_str!("asm/core/create.asm"), @@ -69,6 +75,7 @@ pub(crate) fn combined_kernel() -> Kernel { include_str!("asm/main.asm"), include_str!("asm/memory/core.asm"), include_str!("asm/memory/memcpy.asm"), + include_str!("asm/memory/memset.asm"), include_str!("asm/memory/metadata.asm"), include_str!("asm/memory/packing.asm"), include_str!("asm/memory/syscalls.asm"), diff --git a/evm/src/cpu/kernel/asm/bignum/add.asm b/evm/src/cpu/kernel/asm/bignum/add.asm new file mode 100644 index 00000000..508078ce --- /dev/null +++ b/evm/src/cpu/kernel/asm/bignum/add.asm @@ -0,0 +1,56 @@ +// Arithmetic on little-endian integers represented with 128-bit limbs. +// All integers must be under a given length bound, and are padded with leading zeroes. + +// Replaces a with a + b, leaving b unchanged. +global add_bignum: + // stack: len, a_start_loc, b_start_loc, retdest + PUSH 0 + // stack: carry=0, i=len, a_start_loc, b_start_loc, retdest +add_loop: + // stack: carry, i, a_cur_loc, b_cur_loc, retdest + DUP4 + %mload_kernel_general + // stack: b[cur], carry, i, a_cur_loc, b_cur_loc, retdest + DUP4 + %mload_kernel_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 + %shl_const(128) + %shr_const(128) + // 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_kernel_general + // stack: carry_new, i, a_cur_loc, b_cur_loc, retdest + %stack (c, i, a, b) -> (a, b, c, i) + // stack: a_cur_loc, b_cur_loc, carry_new, i, retdest + %increment + // stack: a_cur_loc + 1, b_cur_loc, carry_new, i, retdest + SWAP1 + // stack: b_cur_loc, a_cur_loc + 1, carry_new, i, retdest + %increment + // stack: b_cur_loc + 1, a_cur_loc + 1, carry_new, i, retdest + %stack (b, a, c, i) -> (i, c, a, b) + // stack: i, carry_new, a_cur_loc + 1, b_cur_loc + 1, retdest + %decrement + // stack: i - 1, carry_new, a_cur_loc + 1, b_cur_loc + 1, retdest + SWAP1 + // stack: carry_new, i - 1, a_cur_loc + 1, b_cur_loc + 1, retdest + DUP2 + // stack: i - 1, carry_new, 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, retdest + SWAP1 + // stack: retdest, carry_new + JUMP diff --git a/evm/src/cpu/kernel/asm/bignum/ge.asm b/evm/src/cpu/kernel/asm/bignum/ge.asm new file mode 100644 index 00000000..cdd7712f --- /dev/null +++ b/evm/src/cpu/kernel/asm/bignum/ge.asm @@ -0,0 +1,80 @@ +// Arithmetic on little-endian integers represented with 128-bit limbs. +// All integers must be under a given length bound, and are padded with leading zeroes. + +// Returns a >= b. +global ge_bignum: + // stack: len, a_start_loc, b_start_loc, retdest + SWAP1 + // stack: a_start_loc, len, b_start_loc, retdest + DUP2 + // stack: len, a_start_loc, len, b_start_loc, retdest + ADD + %decrement + // stack: a_end_loc, len, b_start_loc, retdest + SWAP2 + // stack: b_start_loc, len, a_end_loc, retdest + DUP2 + // stack: len, b_start_loc, len, a_end_loc, retdest + ADD + %decrement + // 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 + %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_kernel_general + SWAP1 + %mload_kernel_general + SWAP1 + // stack: a[i], b[i], i, 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 + LT + %jumpi(less) + // stack: i, 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 + SWAP2 + // stack: b_i_loc, i-1, a_i_loc_new, 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 + %jump(ge_loop) +equal: + // stack: i, a_i_loc, b_i_loc, retdest + %pop3 + // stack: retdest + PUSH 3 + // stack: 3, retdest + SWAP1 + JUMP +greater: + // stack: a[i], b[i], i, a_i_loc, b_i_loc, retdest + %pop5 + // stack: retdest + PUSH 1 + // stack: 1, retdest + SWAP1 + JUMP +less: + // stack: i, a_i_loc, b_i_loc, retdest + %pop3 + // stack: retdest + PUSH 0 + // stack: 0, retdest + SWAP1 + JUMP diff --git a/evm/src/cpu/kernel/asm/bignum/iszero.asm b/evm/src/cpu/kernel/asm/bignum/iszero.asm new file mode 100644 index 00000000..ff755270 --- /dev/null +++ b/evm/src/cpu/kernel/asm/bignum/iszero.asm @@ -0,0 +1,36 @@ +// Arithmetic on little-endian integers represented with 128-bit limbs. +// All integers must be under a given length bound, and are padded with leading zeroes. + +global iszero_bignum: + // stack: len, start_loc, retdest + DUP2 + // stack: start_loc, len, start_loc, retdest + ADD + // stack: end_loc, start_loc, retdest + SWAP1 + // stack: cur_loc=start_loc, end_loc, retdest +iszero_loop: + // stack: cur_loc, end_loc, retdest + DUP1 + // stack: cur_loc, cur_loc, end_loc, retdest + %mload_kernel_general + // stack: cur_val, cur_loc, end_loc, retdest + %jumpi(neqzero) + // stack: cur_loc, end_loc, retdest + %increment + // stack: cur_loc + 1, end_loc, retdest + %stack (vals: 2) -> (vals, vals) + // stack: cur_loc + 1, end_loc, cur_loc + 1, end_loc, retdest + EQ + %jumpi(eqzero) + %jump(iszero_loop) +neqzero: + // stack: cur_loc, end_loc, retdest + %stack (vals: 2, retdest) -> (retdest, 0) + // stack: retdest, 0 + JUMP +eqzero: + // stack: cur_loc, end_loc, retdest + %stack (vals: 2, retdest) -> (retdest, 1) + // stack: retdest, 1 + JUMP diff --git a/evm/src/cpu/kernel/asm/bignum/mul.asm b/evm/src/cpu/kernel/asm/bignum/mul.asm new file mode 100644 index 00000000..d96518fe --- /dev/null +++ b/evm/src/cpu/kernel/asm/bignum/mul.asm @@ -0,0 +1,202 @@ +// Arithmetic on little-endian integers represented with 128-bit limbs. +// All integers must be under a given length bound, and are padded with leading zeroes. + +// Multiplies a bignum by a single-limb value. Resulting limbs may be larger than 128 bits. +// This is a naive multiplication algorithm (BasecaseMultiply from Modern Computer Arithmetic). +mul_bignum_helper: + // stack: len, start_loc, val, retdest + DUP2 + // stack: start_loc, len, start_loc, val, retdest + ADD + // stack: end_loc, start_loc, val, retdest + SWAP2 + SWAP1 + // stack: i=start_loc, val, end_loc, retdest +mul_helper_loop: + // stack: i, val, end_loc, retdest + DUP1 + // stack: i, i, val, end_loc, retdest + %mload_kernel_general + // stack: bignum[i], i, val, end_loc, retdest + DUP3 + // stack: val, bignum[i], i, val, end_loc, retdest + MUL + // stack: val * bignum[i], i, val, end_loc, retdest + DUP2 + // stack: i, val * bignum[i], i, val, end_loc, retdest + %mstore_kernel_general + // stack: i, val, end_loc, retdest + %increment + // stack: i + 1, val, end_loc, retdest + DUP1 + // stack: i + 1, i + 1, val, end_loc, retdest + DUP4 + // stack: end_loc, i + 1, i + 1, val, end_loc, retdest + GT + %jumpi(mul_helper_loop) + // stack: n = 0, i, val, retdest + %pop3 + // stack: retdest + JUMP + +// Reduces a bignum with limbs possibly greater than 128 bits to a normalized bignum with length len + 1. +// Used after `mul_bignum_helper` to complete the process of multiplying a bignum by a constant value. +mul_bignum_reduce_helper: + // stack: len, start_loc, retdest + DUP2 + // stack: start_loc, len, start_loc, retdest + ADD + // stack: end_loc, start_loc, retdest + SWAP1 + // stack: i=start_loc, end_loc, retdest +reduce_loop: + // stack: i, end_loc, retdest + DUP1 + // stack: i, i, end_loc, retdest + %mload_kernel_general + // stack: bignum[i], i, end_loc, retdest + DUP1 + // stack: bignum[i], bignum[i], i, end_loc, retdest + %shl_const(128) + %shr_const(128) + // stack: bignum[i] % 2^128, bignum[i], i, end_loc, retdest + SWAP1 + // stack: bignum[i], bignum[i] % 2^128, i, end_loc, retdest + %shr_const(128) + // stack: bignum[i] // 2^128, bignum[i] % 2^128, i, end_loc, retdest + DUP3 + // stack: i, bignum[i] // 2^128, bignum[i] % 2^128, i, end_loc, retdest + %increment + // stack: i+1, bignum[i] // 2^128, bignum[i] % 2^128, i, end_loc, retdest + SWAP1 + // stack: bignum[i] // 2^128, i+1, bignum[i] % 2^128, i, end_loc, retdest + DUP2 + // stack: i+1, bignum[i] // 2^128, i+1, bignum[i] % 2^128, i, end_loc, retdest + %mload_kernel_general + // stack: bignum[i+1], bignum[i] // 2^128, i+1, bignum[i] % 2^128, i, end_loc, retdest + ADD + // stack: bignum[i+1] + bignum[i] // 2^128, i+1, bignum[i] % 2^128, i, end_loc, retdest + SWAP1 + // stack: i+1, bignum[i+1] + bignum[i] // 2^128, bignum[i] % 2^128, i, end_loc, retdest + %mstore_kernel_general + // stack: bignum[i] % 2^128, i, end_loc, retdest + DUP2 + // stack: i, bignum[i] % 2^128, i, end_loc, retdest + %mstore_kernel_general + // stack: i, end_loc, retdest + %increment + // stack: i + 1, end_loc, retdest + %stack (vals: 2) -> (vals, vals) + // stack: i + 1, end_loc, i + 1, end_loc, retdest + EQ + %jumpi(reduce_loop) +reduce_end: + // stack: n = 0, i, retdest + %pop2 + // stack: retdest + JUMP + +// Stores a * b in output_loc, leaving a and b unchanged. +// Both a and b have length len; a * b will have length 2 * len. +// Both output_loc and scratch_space must be initialized as zeroes (2 * len of them in the case +// of output_loc, and len + 1 of them in the case of scratch_space). +global mul_bignum: + // stack: len, a_start_loc, b_start_loc, output_loc, scratch_space, retdest + DUP1 + // stack: len, n=len, a_start_loc, bi=b_start_loc, output_cur=output_loc, scratch_space, retdest +mul_loop: + // stack: len, n, a_start_loc, bi, output_cur, scratch_space, retdest + + // Copy a from a_start_loc into scratch_space. + DUP1 + // stack: len, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + DUP4 + // stack: a_start_loc, len, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + DUP8 + // stack: scratch_space, a_start_loc, len, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + %memcpy_kernel_general + // stack: len, n, a_start_loc, bi, output_cur, scratch_space, retdest + + // Insert a zero into scratch_space[len]. + DUP6 + // stack: scratch_space, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + DUP2 + // stack: len, scratch_space, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + ADD + // stack: scratch_space + len, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + PUSH 0 + SWAP1 + // stack: scratch_space + len, 0, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + %mstore_kernel_general + // stack: len, n, a_start_loc, bi, output_cur, scratch_space, retdest + + // Use scratch_space to multiply a by b[i]. + PUSH mul_return_1 + // stack: mul_return_1, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + DUP5 + // stack: bi, mul_return_1, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + %mload_kernel_general + // stack: b[i], mul_return_1, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + DUP8 + // stack: scratch_space, b[i], mul_return_1, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + DUP4 + // stack: len, scratch_space, b[i], mul_return_1, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + %jump(mul_bignum_helper) +mul_return_1: + // stack: len, n, a_start_loc, bi, output_cur, scratch_space, retdest + PUSH mul_return_2 + // stack: mul_return_2, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + DUP7 + // stack: scratch_space, mul_return_2, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + DUP3 + // stack: len, scratch_space, mul_return_2, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + %jump(mul_bignum_reduce_helper) +mul_return_2: + // stack: len, n, a_start_loc, bi, output_cur, scratch_space, retdest + + // Add the multiplication result into output_cur = output_len[i]. + PUSH mul_return_3 + // stack: mul_return_3, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + DUP7 + // stack: scratch_space, mul_return_3, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + DUP7 + // stack: output_cur, scratch_space, mul_return_3, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + DUP4 + // stack: len, output_cur, scratch_space, mul_return_3, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + %increment + // stack: len + 1, output_cur, scratch_space, mul_return_3, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + %jump(add_bignum) +mul_return_3: + // stack: carry, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + DUP6 + // stack: output_cur, carry, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + DUP3 + // stack: len, output_cur, carry, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + ADD + // stack: output_cur + len, carry, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + %increment + // stack: output_cur + len + 1, carry, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + %mstore_kernel_general + // stack: len, n, a_start_loc, bi, output_cur, scratch_space, retdest + + // Increment output_cur and b[i], decrement n, and check if we're done. + DUP5 + // stack: output_cur, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + %increment + // stack: output_cur+1, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + DUP5 + %increment + // stack: bi+1, output_cur+1, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + DUP5 + // stack: a_start_loc, bi+1, output_cur+1, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + DUP5 + %decrement + // stack: n-1, a_start_loc, bi+1, output_cur+1, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + %stack (new: 4, len, old: 4) -> (len, new) + // stack: len, n-1, a_start_loc, bi+1, output_cur+1, scratch_space, retdest + DUP2 + // stack: n-1, len, n-1, a_start_loc, bi+1, output_cur+1, scratch_space, retdest + %jumpi(mul_loop) + // stack: len, n, a_start_loc, bi, output_cur, scratch_space, retdest + %pop6 + JUMP diff --git a/evm/src/cpu/kernel/asm/bignum/shr.asm b/evm/src/cpu/kernel/asm/bignum/shr.asm new file mode 100644 index 00000000..69d32b07 --- /dev/null +++ b/evm/src/cpu/kernel/asm/bignum/shr.asm @@ -0,0 +1,56 @@ +// Arithmetic on little-endian integers represented with 128-bit limbs. +// All integers must be under a given length bound, and are padded with leading zeroes. + +// Shifts a given bignum right by one bit (in place). +global shr_bignum: + // stack: len, start_loc, retdest + DUP2 + // stack: start_loc, len, start_loc, retdest + ADD + // 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 +shr_loop: + // stack: i, carry, start_loc, retdest + DUP1 + // stack: i, i, carry, start_loc, retdest + %mload_kernel_general + // stack: a[i], i, carry, start_loc, retdest + DUP1 + // stack: a[i], a[i], i, carry, start_loc, retdest + %shr_const(1) + // stack: a[i] >> 1, a[i], i, carry, start_loc, retdest + SWAP1 + // stack: a[i], a[i] >> 1, i, 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 + %shl_const(127) + // stack: carry << 127, a[i] >> 1, i, new_carry, start_loc, retdest + OR + // stack: carry << 127 | a[i] >> 1, i, new_carry, start_loc, retdest + DUP2 + // stack: i, carry << 127 | a[i] >> 1, i, new_carry, start_loc, retdest + %mstore_kernel_general + // stack: i, new_carry, start_loc, retdest + DUP1 + // stack: i, i, new_carry, start_loc, retdest + %decrement + // stack: i-1, i, 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 + EQ + // stack: i == start_loc, i-1, new_carry, start_loc, retdest + ISZERO + // stack: i != start_loc, i-1, new_carry, start_loc, retdest + %jumpi(shr_loop) +shr_end: + // stack: i, new_carry, start_loc, retdest + %pop3 + // stack: retdest + JUMP diff --git a/evm/src/cpu/kernel/asm/bignum/util.asm b/evm/src/cpu/kernel/asm/bignum/util.asm new file mode 100644 index 00000000..2c6b2185 --- /dev/null +++ b/evm/src/cpu/kernel/asm/bignum/util.asm @@ -0,0 +1,13 @@ +%macro memcpy_kernel_general + // stack: dst, src, len + %stack (dst, src, len) -> (0, @SEGMENT_KERNEL_GENERAL, dst, 0, @SEGMENT_KERNEL_GENERAL, src, len, %%after) + %jump(memcpy) +%%after: +%endmacro + +%macro clear_kernel_general + // stack: dst, len + %stack (dst, len) -> (0, @SEGMENT_KERNEL_GENERAL, dst, 0, len, %%after) + %jump(memset) +%%after: +%endmacro diff --git a/evm/src/cpu/kernel/asm/memory/memset.asm b/evm/src/cpu/kernel/asm/memory/memset.asm new file mode 100644 index 00000000..77b37f64 --- /dev/null +++ b/evm/src/cpu/kernel/asm/memory/memset.asm @@ -0,0 +1,38 @@ +// Sets `count` values to `value` at +// DST = (dst_ctx, dst_segment, dst_addr). +// This tuple definition is used for brevity in the stack comments below. +global memset: + // stack: DST, value, count, retdest + DUP5 + // stack: count, DST, value, count, retdest + ISZERO + // stack: count == 0, DST, value, count, retdest + %jumpi(memset_finish) + // stack: DST, value, count, retdest + + DUP4 + // stack: value, DST, value, count, retdest + DUP4 + DUP4 + DUP4 + // stack: DST, value, DST, value, count, retdest + MSTORE_GENERAL + // stack: DST, value, count, retdest + + // Increment dst_addr. + SWAP2 + %increment + SWAP2 + // Decrement count. + SWAP4 + %decrement + SWAP4 + + // Continue the loop. + %jump(memset) + +memset_finish: + // stack: DST, value, count, retdest + %pop5 + // stack: retdest + JUMP diff --git a/evm/src/cpu/kernel/asm/util/basic_macros.asm b/evm/src/cpu/kernel/asm/util/basic_macros.asm index a68d832d..2c27efa3 100644 --- a/evm/src/cpu/kernel/asm/util/basic_macros.asm +++ b/evm/src/cpu/kernel/asm/util/basic_macros.asm @@ -50,6 +50,14 @@ %endrep %endmacro +%macro neq + // stack: x, y + EQ + // stack: x == y + ISZERO + // stack: x != y +%endmacro + %macro and_const(c) // stack: input, ... PUSH $c diff --git a/evm/src/cpu/kernel/constants/mod.rs b/evm/src/cpu/kernel/constants/mod.rs index afabd955..d0a079b8 100644 --- a/evm/src/cpu/kernel/constants/mod.rs +++ b/evm/src/cpu/kernel/constants/mod.rs @@ -19,7 +19,11 @@ pub(crate) mod txn_fields; pub fn evm_constants() -> HashMap { let mut c = HashMap::new(); - let hex_constants = EC_CONSTANTS.iter().chain(HASH_CONSTANTS.iter()).cloned(); + let hex_constants = MISC_CONSTANTS + .iter() + .chain(EC_CONSTANTS.iter()) + .chain(HASH_CONSTANTS.iter()) + .cloned(); for (name, value) in hex_constants { c.insert(name.into(), U256::from_big_endian(&value)); } @@ -50,6 +54,14 @@ pub fn evm_constants() -> HashMap { c } +const MISC_CONSTANTS: [(&str, [u8; 32]); 1] = [ + // Base for limbs used in bignum arithmetic. + ( + "BIGNUM_LIMB_BASE", + hex!("0000000000000000000000000000000100000000000000000000000000000000"), + ), +]; + const HASH_CONSTANTS: [(&str, [u8; 32]); 2] = [ // Hash of an empty string: keccak(b'').hex() ( diff --git a/evm/src/cpu/kernel/evm_asm.pest b/evm/src/cpu/kernel/evm_asm.pest index e7337430..3243aecc 100644 --- a/evm/src/cpu/kernel/evm_asm.pest +++ b/evm/src/cpu/kernel/evm_asm.pest @@ -26,7 +26,7 @@ stack = { ^"%stack" ~ stack_placeholders ~ "->" ~ stack_replacements } stack_placeholders = { "(" ~ (stack_placeholder ~ ("," ~ stack_placeholder)*)? ~ ")" } stack_placeholder = { stack_block | identifier } stack_block = { identifier ~ ":" ~ literal_decimal } -stack_replacements = { "(" ~ stack_replacement ~ ("," ~ stack_replacement)* ~ ")" } +stack_replacements = { "(" ~ (stack_replacement ~ ("," ~ stack_replacement)*)? ~ ")" } stack_replacement = { literal | identifier | constant | macro_label | variable } global_label_decl = ${ ^"GLOBAL " ~ identifier ~ ":" } diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 843f0a0d..b0d3a784 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -194,6 +194,12 @@ impl<'a> Interpreter<'a> { &mut self.generation_state.memory.contexts[0].segments[Segment::TrieData as usize].content } + pub(crate) fn get_memory_segment(&self, segment: Segment) -> Vec { + self.generation_state.memory.contexts[0].segments[segment as usize] + .content + .clone() + } + pub(crate) fn get_memory_segment_bytes(&self, segment: Segment) -> Vec { self.generation_state.memory.contexts[0].segments[segment as usize] .content @@ -202,10 +208,22 @@ impl<'a> Interpreter<'a> { .collect() } + pub(crate) fn get_kernel_general_memory(&self) -> Vec { + self.get_memory_segment(Segment::KernelGeneral) + } + pub(crate) fn get_rlp_memory(&self) -> Vec { self.get_memory_segment_bytes(Segment::RlpRaw) } + pub(crate) fn set_memory_segment(&mut self, segment: Segment, memory: Vec) { + self.generation_state.memory.contexts[0].segments[segment as usize].content = memory; + } + + pub(crate) fn set_kernel_general_memory(&mut self, memory: Vec) { + self.set_memory_segment(Segment::KernelGeneral, memory) + } + pub(crate) fn set_memory_segment_bytes(&mut self, segment: Segment, memory: Vec) { self.generation_state.memory.contexts[0].segments[segment as usize].content = memory.into_iter().map(U256::from).collect(); diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs new file mode 100644 index 00000000..f866caad --- /dev/null +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -0,0 +1,222 @@ +use anyhow::Result; +use ethereum_types::U256; +use itertools::Itertools; +use num::{BigUint, Signed}; +use num_bigint::RandBigInt; + +use crate::cpu::kernel::aggregator::KERNEL; +use crate::cpu::kernel::interpreter::Interpreter; +use crate::util::{biguint_to_mem_vec, mem_vec_to_biguint}; + +fn pack_bignums(biguints: &[BigUint], length: usize) -> Vec { + biguints + .iter() + .flat_map(|biguint| { + biguint_to_mem_vec(biguint.clone()) + .into_iter() + .pad_using(length, |_| U256::zero()) + }) + .collect() +} + +fn gen_bignum(bit_size: usize) -> BigUint { + let mut rng = rand::thread_rng(); + rng.gen_bigint(bit_size as u64).abs().to_biguint().unwrap() +} + +fn bignum_len(a: &BigUint) -> usize { + (a.bits() as usize) / 128 + 1 +} + +fn gen_two_bignums_ordered(bit_size: usize) -> (BigUint, BigUint) { + let mut rng = rand::thread_rng(); + let (a, b) = { + let a = rng.gen_bigint(bit_size as u64).abs().to_biguint().unwrap(); + let b = rng.gen_bigint(bit_size as u64).abs().to_biguint().unwrap(); + (a.clone().max(b.clone()), a.min(b)) + }; + + (a, b) +} + +fn prepare_bignum(bit_size: usize) -> (BigUint, U256, Vec) { + let a = gen_bignum(bit_size); + let length: U256 = bignum_len(&a).into(); + let a_limbs = biguint_to_mem_vec(a.clone()); + + (a, length, a_limbs) +} + +fn prepare_two_bignums(bit_size: usize) -> (BigUint, BigUint, U256, Vec) { + let (a, b) = gen_two_bignums_ordered(bit_size); + let length: U256 = bignum_len(&a).into(); + let memory = pack_bignums(&[a.clone(), b.clone()], length.try_into().unwrap()); + + (a, b, length, memory) +} + +#[test] +fn test_shr_bignum() -> Result<()> { + let (a, length, memory) = prepare_bignum(1000); + + let halved = a >> 1; + + let retdest = 0xDEADBEEFu32.into(); + let shr_bignum = KERNEL.global_labels["shr_bignum"]; + + let a_start_loc = 0.into(); + + let mut initial_stack: Vec = vec![length, a_start_loc, retdest]; + initial_stack.reverse(); + let mut interpreter = Interpreter::new_with_kernel(shr_bignum, initial_stack); + interpreter.set_kernel_general_memory(memory); + interpreter.run()?; + + let new_memory = interpreter.get_kernel_general_memory(); + let new_a = mem_vec_to_biguint(&new_memory[0..length.as_usize()]); + assert_eq!(new_a, halved); + + Ok(()) +} + +#[test] +fn test_iszero_bignum() -> Result<()> { + let (_a, length, memory) = prepare_bignum(1000); + + let retdest = 0xDEADBEEFu32.into(); + let iszero_bignum = KERNEL.global_labels["iszero_bignum"]; + + let a_start_loc = 0.into(); + + // Test with a > 0. + let mut initial_stack: Vec = vec![length, a_start_loc, retdest]; + initial_stack.reverse(); + let mut interpreter = Interpreter::new_with_kernel(iszero_bignum, initial_stack); + interpreter.set_kernel_general_memory(memory.clone()); + interpreter.run()?; + let result = interpreter.stack()[0]; + assert_eq!(result, 0.into()); + + let memory = vec![0.into(); memory.len()]; + + // Test with a == 0. + let mut initial_stack: Vec = vec![length, a_start_loc, retdest]; + initial_stack.reverse(); + let mut interpreter = Interpreter::new_with_kernel(iszero_bignum, initial_stack); + interpreter.set_kernel_general_memory(memory); + interpreter.run()?; + let result = interpreter.stack()[0]; + assert_eq!(result, U256::one()); + + Ok(()) +} + +#[test] +fn test_ge_bignum() -> Result<()> { + let (_a, _b, length, memory) = prepare_two_bignums(1000); + + let retdest = 0xDEADBEEFu32.into(); + let ge_bignum = KERNEL.global_labels["ge_bignum"]; + + let a_start_loc = 0.into(); + let b_start_loc = length; + + // Test with a > b. + let mut initial_stack: Vec = vec![length, a_start_loc, b_start_loc, retdest]; + initial_stack.reverse(); + let mut interpreter = Interpreter::new_with_kernel(ge_bignum, initial_stack); + interpreter.set_kernel_general_memory(memory.clone()); + interpreter.run()?; + let result = interpreter.stack()[0]; + assert_eq!(result, U256::one()); + + // Swap a and b, to test the less-than case. + let mut initial_stack: Vec = vec![length, b_start_loc, a_start_loc, retdest]; + initial_stack.reverse(); + let mut interpreter = Interpreter::new_with_kernel(ge_bignum, initial_stack); + interpreter.set_kernel_general_memory(memory); + interpreter.run()?; + let result = interpreter.stack()[0]; + assert_eq!(result, 0.into()); + + Ok(()) +} + +#[test] +fn test_add_bignum() -> Result<()> { + let (a, b, length, memory) = prepare_two_bignums(1000); + + // Determine expected sum. + let sum = a + b; + let expected_sum: Vec = biguint_to_mem_vec(sum); + + let a_start_loc = 0.into(); + let b_start_loc = length; + + // Prepare stack. + let retdest = 0xDEADBEEFu32.into(); + let mut initial_stack: Vec = vec![length, a_start_loc, b_start_loc, retdest]; + initial_stack.reverse(); + + // Prepare interpreter. + let add_bignum = KERNEL.global_labels["add_bignum"]; + let mut interpreter = Interpreter::new_with_kernel(add_bignum, initial_stack); + interpreter.set_kernel_general_memory(memory); + + // Run add function. + interpreter.run()?; + + // Determine actual sum. + let new_memory = interpreter.get_kernel_general_memory(); + let actual_sum: Vec<_> = new_memory[..expected_sum.len()].into(); + + // Compare. + assert_eq!(actual_sum, expected_sum); + + Ok(()) +} + +#[test] +fn test_mul_bignum() -> Result<()> { + let (a, b, length, memory) = prepare_two_bignums(1000); + + // Determine expected product. + let product = a * b; + let expected_product: Vec = biguint_to_mem_vec(product); + + // Output and scratch space locations (initialized as zeroes) follow a and b in memory. + let a_start_loc = 0.into(); + let b_start_loc = length; + let output_loc = length * 2; + let scratch_space = length * 4; + + // Prepare stack. + let retdest = 0xDEADBEEFu32.into(); + let mut initial_stack: Vec = vec![ + length, + a_start_loc, + b_start_loc, + output_loc, + scratch_space, + retdest, + ]; + initial_stack.reverse(); + + // Prepare interpreter. + let mul_bignum = KERNEL.global_labels["mul_bignum"]; + let mut interpreter = Interpreter::new_with_kernel(mul_bignum, initial_stack); + interpreter.set_kernel_general_memory(memory); + + // Run mul function. + interpreter.run()?; + + // Determine actual product. + let new_memory = interpreter.get_kernel_general_memory(); + let output_location: usize = output_loc.try_into().unwrap(); + let actual_product: Vec<_> = + new_memory[output_location..output_location + expected_product.len()].into(); + + assert_eq!(actual_product, expected_product); + + Ok(()) +} diff --git a/evm/src/cpu/kernel/tests/mod.rs b/evm/src/cpu/kernel/tests/mod.rs index acf90230..6fb9ee4a 100644 --- a/evm/src/cpu/kernel/tests/mod.rs +++ b/evm/src/cpu/kernel/tests/mod.rs @@ -1,5 +1,6 @@ mod account_code; mod balance; +mod bignum; mod core; mod ecc; mod exp; diff --git a/evm/src/keccak/keccak_stark.rs b/evm/src/keccak/keccak_stark.rs index c8fe8086..61651dd5 100644 --- a/evm/src/keccak/keccak_stark.rs +++ b/evm/src/keccak/keccak_stark.rs @@ -68,7 +68,7 @@ impl, const D: usize> KeccakStark { let pad_rows = self.generate_trace_rows_for_perm([0; NUM_INPUTS]); while rows.len() < num_rows { - rows.extend(&pad_rows); + rows.extend(pad_rows.clone()); } rows.drain(num_rows..); rows diff --git a/evm/src/util.rs b/evm/src/util.rs index dcb0a8ef..55344dcb 100644 --- a/evm/src/util.rs +++ b/evm/src/util.rs @@ -144,3 +144,41 @@ pub(crate) fn biguint_to_u256(x: BigUint) -> U256 { let bytes = x.to_bytes_le(); U256::from_little_endian(&bytes) } + +pub(crate) fn le_limbs_to_biguint(x: &[u128]) -> BigUint { + BigUint::from_slice( + &x.iter() + .flat_map(|&a| { + [ + (a % (1 << 32)) as u32, + ((a >> 32) % (1 << 32)) as u32, + ((a >> 64) % (1 << 32)) as u32, + ((a >> 96) % (1 << 32)) as u32, + ] + }) + .collect::>(), + ) +} + +pub(crate) fn mem_vec_to_biguint(x: &[U256]) -> BigUint { + le_limbs_to_biguint(&x.iter().map(|&n| n.try_into().unwrap()).collect_vec()) +} + +pub(crate) fn biguint_to_le_limbs(x: BigUint) -> Vec { + let mut digits = x.to_u32_digits(); + + // Pad to a multiple of 8. + digits.resize((digits.len() + 7) / 8 * 8, 0); + + digits + .chunks(4) + .map(|c| (c[3] as u128) << 96 | (c[2] as u128) << 64 | (c[1] as u128) << 32 | c[0] as u128) + .collect() +} + +pub(crate) fn biguint_to_mem_vec(x: BigUint) -> Vec { + biguint_to_le_limbs(x) + .into_iter() + .map(|n| n.into()) + .collect() +} diff --git a/plonky2/src/fri/recursive_verifier.rs b/plonky2/src/fri/recursive_verifier.rs index 8e9329d5..307c4785 100644 --- a/plonky2/src/fri/recursive_verifier.rs +++ b/plonky2/src/fri/recursive_verifier.rs @@ -78,16 +78,12 @@ impl, const D: usize> CircuitBuilder { assert!( self.config.num_wires >= min_wires, - "To efficiently perform FRI checks with an arity of 2^{}, at least {} wires are needed. Consider reducing arity.", - max_fri_arity_bits, - min_wires + "To efficiently perform FRI checks with an arity of 2^{max_fri_arity_bits}, at least {min_wires} wires are needed. Consider reducing arity." ); assert!( self.config.num_routed_wires >= min_routed_wires, - "To efficiently perform FRI checks with an arity of 2^{}, at least {} routed wires are needed. Consider reducing arity.", - max_fri_arity_bits, - min_routed_wires + "To efficiently perform FRI checks with an arity of 2^{max_fri_arity_bits}, at least {min_routed_wires} routed wires are needed. Consider reducing arity." ); } diff --git a/plonky2/src/gadgets/split_base.rs b/plonky2/src/gadgets/split_base.rs index dd0edf5d..7558be3d 100644 --- a/plonky2/src/gadgets/split_base.rs +++ b/plonky2/src/gadgets/split_base.rs @@ -38,8 +38,7 @@ impl, const D: usize> CircuitBuilder { let num_bits = bits.len(); assert!( num_bits <= log_floor(F::ORDER, 2), - "{} bits may overflow the field", - num_bits + "{num_bits} bits may overflow the field" ); if num_bits == 0 { return self.zero(); diff --git a/plonky2/src/gates/random_access.rs b/plonky2/src/gates/random_access.rs index 80874505..b74b1169 100644 --- a/plonky2/src/gates/random_access.rs +++ b/plonky2/src/gates/random_access.rs @@ -361,9 +361,7 @@ impl, const D: usize> SimpleGenerator let access_index = access_index_f.to_canonical_u64() as usize; debug_assert!( access_index < vec_size, - "Access index {} is larger than the vector size {}", - access_index, - vec_size + "Access index {access_index} is larger than the vector size {vec_size}" ); set_local_wire( diff --git a/plonky2/src/hash/merkle_tree.rs b/plonky2/src/hash/merkle_tree.rs index e884554f..beb22b07 100644 --- a/plonky2/src/hash/merkle_tree.rs +++ b/plonky2/src/hash/merkle_tree.rs @@ -136,9 +136,7 @@ impl> MerkleTree { let log2_leaves_len = log2_strict(leaves.len()); assert!( cap_height <= log2_leaves_len, - "cap_height={} should be at most log2(leaves.len())={}", - cap_height, - log2_leaves_len + "cap_height={cap_height} should be at most log2(leaves.len())={log2_leaves_len}" ); let num_digests = 2 * (leaves.len() - (1 << cap_height)); diff --git a/plonky2/src/iop/generator.rs b/plonky2/src/iop/generator.rs index a65d1748..80eb0094 100644 --- a/plonky2/src/iop/generator.rs +++ b/plonky2/src/iop/generator.rs @@ -89,8 +89,7 @@ pub(crate) fn generate_partial_witness< assert_eq!( remaining_generators, 0, - "{} generators weren't run", - remaining_generators, + "{remaining_generators} generators weren't run", ); witness diff --git a/plonky2/src/iop/witness.rs b/plonky2/src/iop/witness.rs index 14213d0d..d0e3e7e4 100644 --- a/plonky2/src/iop/witness.rs +++ b/plonky2/src/iop/witness.rs @@ -284,8 +284,7 @@ impl WitnessWrite for PartialWitness { if let Some(old_value) = opt_old_value { assert_eq!( value, old_value, - "Target {:?} was set twice with different values: {} != {}", - target, old_value, value + "Target {target:?} was set twice with different values: {old_value} != {value}" ); } } @@ -325,8 +324,7 @@ impl<'a, F: Field> PartitionWitness<'a, F> { if let Some(old_value) = *rep_value { assert_eq!( value, old_value, - "Partition containing {:?} was set twice with different values: {} != {}", - target, old_value, value + "Partition containing {target:?} was set twice with different values: {old_value} != {value}" ); None } else { From aa605b673b25d0ef09725f1a00fb0a6235c7ad52 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Mon, 13 Feb 2023 10:47:30 -0800 Subject: [PATCH 02/62] flag functions used only in tests --- evm/src/util.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/evm/src/util.rs b/evm/src/util.rs index 55344dcb..6b2ca479 100644 --- a/evm/src/util.rs +++ b/evm/src/util.rs @@ -145,6 +145,7 @@ pub(crate) fn biguint_to_u256(x: BigUint) -> U256 { U256::from_little_endian(&bytes) } +#[cfg(test)] pub(crate) fn le_limbs_to_biguint(x: &[u128]) -> BigUint { BigUint::from_slice( &x.iter() @@ -160,10 +161,12 @@ pub(crate) fn le_limbs_to_biguint(x: &[u128]) -> BigUint { ) } +#[cfg(test)] pub(crate) fn mem_vec_to_biguint(x: &[U256]) -> BigUint { le_limbs_to_biguint(&x.iter().map(|&n| n.try_into().unwrap()).collect_vec()) } +#[cfg(test)] pub(crate) fn biguint_to_le_limbs(x: BigUint) -> Vec { let mut digits = x.to_u32_digits(); @@ -176,6 +179,7 @@ pub(crate) fn biguint_to_le_limbs(x: BigUint) -> Vec { .collect() } +#[cfg(test)] pub(crate) fn biguint_to_mem_vec(x: BigUint) -> Vec { biguint_to_le_limbs(x) .into_iter() From 9976a4b04062200e220d8d51b8dc924a5a10c467 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Mon, 13 Feb 2023 12:53:49 -0800 Subject: [PATCH 03/62] addmul initial --- evm/src/cpu/kernel/aggregator.rs | 1 + evm/src/cpu/kernel/asm/bignum/add.asm | 2 +- evm/src/cpu/kernel/asm/bignum/addmul.asm | 99 ++++++++++++++++ evm/src/cpu/kernel/asm/bignum/mul.asm | 141 ++--------------------- evm/src/cpu/kernel/tests/bignum.rs | 2 + 5 files changed, 115 insertions(+), 130 deletions(-) create mode 100644 evm/src/cpu/kernel/asm/bignum/addmul.asm diff --git a/evm/src/cpu/kernel/aggregator.rs b/evm/src/cpu/kernel/aggregator.rs index 53787e48..53584a1f 100644 --- a/evm/src/cpu/kernel/aggregator.rs +++ b/evm/src/cpu/kernel/aggregator.rs @@ -12,6 +12,7 @@ pub static KERNEL: Lazy = Lazy::new(combined_kernel); pub(crate) fn combined_kernel() -> Kernel { let files = vec![ include_str!("asm/bignum/add.asm"), + include_str!("asm/bignum/addmul.asm"), include_str!("asm/bignum/ge.asm"), include_str!("asm/bignum/iszero.asm"), include_str!("asm/bignum/mul.asm"), diff --git a/evm/src/cpu/kernel/asm/bignum/add.asm b/evm/src/cpu/kernel/asm/bignum/add.asm index 508078ce..d38c9701 100644 --- a/evm/src/cpu/kernel/asm/bignum/add.asm +++ b/evm/src/cpu/kernel/asm/bignum/add.asm @@ -5,7 +5,7 @@ global add_bignum: // stack: len, a_start_loc, b_start_loc, retdest PUSH 0 - // stack: carry=0, i=len, a_start_loc, b_start_loc, retdest + // stack: carry=0, 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 diff --git a/evm/src/cpu/kernel/asm/bignum/addmul.asm b/evm/src/cpu/kernel/asm/bignum/addmul.asm new file mode 100644 index 00000000..742bb829 --- /dev/null +++ b/evm/src/cpu/kernel/asm/bignum/addmul.asm @@ -0,0 +1,99 @@ +// Arithmetic on little-endian integers represented with 128-bit limbs. +// All integers must be under a given length bound, and are padded with leading zeroes. + +// Sets a[0:len] += b[0:len] * val. +global addmul_bignum: + // stack: len, a_start_loc, b_start_loc, val, retdest + PUSH 0 + // stack: carry=0, i=len, a_cur_loc=a_start_loc, b_cur_loc=b_start_loc, val, retdest +addmul_loop: + // stack: carry, i, a_cur_loc, b_cur_loc, val, retdest + DUP4 + // stack: b_cur_loc, carry, i, a_cur_loc, b_cur_loc, val, retdest + %mload_kernel_general + // stack: b[cur], carry, i, a_cur_loc, b_cur_loc, val, retdest + DUP6 + // stack: val, b[cur], carry, i, a_cur_loc, b_cur_loc, val, retdest + MUL + // stack: val * b[cur], carry, i, a_cur_loc, b_cur_loc, val, retdest + DUP1 + // stack: val * b[cur], val * b[cur], carry, i, a_cur_loc, b_cur_loc, val, retdest + %shr_const(128) + // stack: (val * b[cur]) // 2^128, val * b[cur], carry, i, a_cur_loc, b_cur_loc, val, retdest + SWAP1 + // stack: val * b[cur], (val * b[cur]) // 2^128, carry, 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, i, a_cur_loc, b_cur_loc, val, retdest + DUP5 + // stack: a_cur_loc, prod_lo, prod_hi, carry, i, a_cur_loc, b_cur_loc, val, retdest + %mload_kernel_general + // stack: a[cur], prod_lo, prod_hi, carry, i, a_cur_loc, b_cur_loc, val, retdest + DUP1 + // stack: a[cur], a[cur], prod_lo, prod_hi, carry, i, a_cur_loc, b_cur_loc, val, retdest + SWAP2 + // stack: prod_lo, a[cur], a[cur], prod_hi, carry, 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, i, a_cur_loc, b_cur_loc, val, retdest + DUP1 + // stack: prod_lo', prod_lo', a[cur], prod_hi, carry, i, a_cur_loc, b_cur_loc, val, retdest + SWAP2 + // stack: a[cur], prod_lo', prod_lo', prod_hi, carry, i, a_cur_loc, b_cur_loc, val, retdest + GT + // stack: prod_lo_carry = a[cur] > prod_lo', prod_lo', prod_hi, carry, i, a_cur_loc, b_cur_loc, val, retdest + SWAP1 + // stack: prod_lo', prod_lo_carry, prod_hi, carry, i, a_cur_loc, b_cur_loc, val, retdest + SWAP2 + // stack: prod_hi, prod_lo_carry, prod_lo', carry, i, a_cur_loc, b_cur_loc, val, retdest + ADD + // stack: prod_hi' = prod_hi + prod_lo_carry, prod_lo', carry, i, a_cur_loc, b_cur_loc, val, retdest + DUP3 + // stack: carry, prod_lo', prod_hi', carry, i, a_cur_loc, b_cur_loc, val, retdest + DUP2 + // stack: prod_lo', carry, prod_lo', prod_hi', carry, i, a_cur_loc, b_cur_loc, val, retdest + ADD + %shl_const(128) + %shr_const(128) + // stack: to_write = (prod_lo' + carry) % 2^128, prod_lo', prod_hi', carry, i, a_cur_loc, b_cur_loc, val, retdest + SWAP1 + // stack: prod_lo', to_write, prod_hi', carry, i, a_cur_loc, b_cur_loc, val, retdest + DUP2 + // stack: to_write, prod_lo', to_write, prod_hi', carry, i, a_cur_loc, b_cur_loc, val, retdest + LT + // stack: carry_new = to_write < prod_lo', to_write, prod_hi', carry, i, a_cur_loc, b_cur_loc, val, retdest + %stack (cn, tw, ph, c) -> (cn, ph, tw) + // stack: carry_new, prod_hi', to_write, i, a_cur_loc, b_cur_loc, val, retdest + ADD + // stack: carry = carry_new' + prod_hi', to_write, i, a_cur_loc, b_cur_loc, val, retdest + SWAP1 + // stack: to_write, carry, i, a_cur_loc, b_cur_loc, val, retdest + DUP4 + // stack: a_cur_loc, to_write, carry, i, a_cur_loc, b_cur_loc, val, retdest + %mstore_kernel_general + // stack: carry, i, a_cur_loc, b_cur_loc, val, retdest + SWAP1 + // stack: i, carry, a_cur_loc, b_cur_loc, val, retdest + %decrement + // stack: i-1, carry, a_cur_loc, b_cur_loc, val, retdest + SWAP2 + // stack: a_cur_loc, carry, i-1, b_cur_loc, val, retdest + %increment + // stack: a_cur_loc+1, carry, i-1, b_cur_loc, val, retdest + SWAP3 + // stack: b_cur_loc, carry, i-1, a_cur_loc+1, val, retdest + %increment + // stack: b_cur_loc+1, carry, i-1, a_cur_loc+1, val, retdest + %stack (b, c, i, a) -> (c, i, a, b) + // stack: carry, i-1, a_cur_loc+1, b_cur_loc+1, val, retdest + DUP2 + // stack: i-1, carry, i-1, a_cur_loc+1, b_cur_loc+1, val, retdest + %jumpi(addmul_loop) +addmul_end: + // stack: carry_new, i-1, a_cur_loc+1, b_cur_loc+1, retdest + %stack (c, i, a, b) -> (c) + // stack: carry_new, retdest + SWAP1 + // stack: retdest, carry_new + JUMP diff --git a/evm/src/cpu/kernel/asm/bignum/mul.asm b/evm/src/cpu/kernel/asm/bignum/mul.asm index d96518fe..1b947c23 100644 --- a/evm/src/cpu/kernel/asm/bignum/mul.asm +++ b/evm/src/cpu/kernel/asm/bignum/mul.asm @@ -1,101 +1,6 @@ // Arithmetic on little-endian integers represented with 128-bit limbs. // All integers must be under a given length bound, and are padded with leading zeroes. -// Multiplies a bignum by a single-limb value. Resulting limbs may be larger than 128 bits. -// This is a naive multiplication algorithm (BasecaseMultiply from Modern Computer Arithmetic). -mul_bignum_helper: - // stack: len, start_loc, val, retdest - DUP2 - // stack: start_loc, len, start_loc, val, retdest - ADD - // stack: end_loc, start_loc, val, retdest - SWAP2 - SWAP1 - // stack: i=start_loc, val, end_loc, retdest -mul_helper_loop: - // stack: i, val, end_loc, retdest - DUP1 - // stack: i, i, val, end_loc, retdest - %mload_kernel_general - // stack: bignum[i], i, val, end_loc, retdest - DUP3 - // stack: val, bignum[i], i, val, end_loc, retdest - MUL - // stack: val * bignum[i], i, val, end_loc, retdest - DUP2 - // stack: i, val * bignum[i], i, val, end_loc, retdest - %mstore_kernel_general - // stack: i, val, end_loc, retdest - %increment - // stack: i + 1, val, end_loc, retdest - DUP1 - // stack: i + 1, i + 1, val, end_loc, retdest - DUP4 - // stack: end_loc, i + 1, i + 1, val, end_loc, retdest - GT - %jumpi(mul_helper_loop) - // stack: n = 0, i, val, retdest - %pop3 - // stack: retdest - JUMP - -// Reduces a bignum with limbs possibly greater than 128 bits to a normalized bignum with length len + 1. -// Used after `mul_bignum_helper` to complete the process of multiplying a bignum by a constant value. -mul_bignum_reduce_helper: - // stack: len, start_loc, retdest - DUP2 - // stack: start_loc, len, start_loc, retdest - ADD - // stack: end_loc, start_loc, retdest - SWAP1 - // stack: i=start_loc, end_loc, retdest -reduce_loop: - // stack: i, end_loc, retdest - DUP1 - // stack: i, i, end_loc, retdest - %mload_kernel_general - // stack: bignum[i], i, end_loc, retdest - DUP1 - // stack: bignum[i], bignum[i], i, end_loc, retdest - %shl_const(128) - %shr_const(128) - // stack: bignum[i] % 2^128, bignum[i], i, end_loc, retdest - SWAP1 - // stack: bignum[i], bignum[i] % 2^128, i, end_loc, retdest - %shr_const(128) - // stack: bignum[i] // 2^128, bignum[i] % 2^128, i, end_loc, retdest - DUP3 - // stack: i, bignum[i] // 2^128, bignum[i] % 2^128, i, end_loc, retdest - %increment - // stack: i+1, bignum[i] // 2^128, bignum[i] % 2^128, i, end_loc, retdest - SWAP1 - // stack: bignum[i] // 2^128, i+1, bignum[i] % 2^128, i, end_loc, retdest - DUP2 - // stack: i+1, bignum[i] // 2^128, i+1, bignum[i] % 2^128, i, end_loc, retdest - %mload_kernel_general - // stack: bignum[i+1], bignum[i] // 2^128, i+1, bignum[i] % 2^128, i, end_loc, retdest - ADD - // stack: bignum[i+1] + bignum[i] // 2^128, i+1, bignum[i] % 2^128, i, end_loc, retdest - SWAP1 - // stack: i+1, bignum[i+1] + bignum[i] // 2^128, bignum[i] % 2^128, i, end_loc, retdest - %mstore_kernel_general - // stack: bignum[i] % 2^128, i, end_loc, retdest - DUP2 - // stack: i, bignum[i] % 2^128, i, end_loc, retdest - %mstore_kernel_general - // stack: i, end_loc, retdest - %increment - // stack: i + 1, end_loc, retdest - %stack (vals: 2) -> (vals, vals) - // stack: i + 1, end_loc, i + 1, end_loc, retdest - EQ - %jumpi(reduce_loop) -reduce_end: - // stack: n = 0, i, retdest - %pop2 - // stack: retdest - JUMP - // Stores a * b in output_loc, leaving a and b unchanged. // Both a and b have length len; a * b will have length 2 * len. // Both output_loc and scratch_space must be initialized as zeroes (2 * len of them in the case @@ -130,43 +35,21 @@ mul_loop: %mstore_kernel_general // stack: len, n, a_start_loc, bi, output_cur, scratch_space, retdest - // Use scratch_space to multiply a by b[i]. - PUSH mul_return_1 - // stack: mul_return_1, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + // Multiply a by b[i] and add into output_cur. + PUSH mul_return + // stack: mul_return, len, n, a_start_loc, bi, output_cur, scratch_space, retdest DUP5 - // stack: bi, mul_return_1, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + // stack: bi, mul_return, len, n, a_start_loc, bi, output_cur, scratch_space, retdest %mload_kernel_general - // stack: b[i], mul_return_1, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + // stack: b[i], mul_return, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + DUP5 + // stack: a_start_loc, b[i], mul_return, len, n, a_start_loc, bi, output_cur, scratch_space, retdest DUP8 - // stack: scratch_space, b[i], mul_return_1, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - DUP4 - // stack: len, scratch_space, b[i], mul_return_1, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - %jump(mul_bignum_helper) -mul_return_1: - // stack: len, n, a_start_loc, bi, output_cur, scratch_space, retdest - PUSH mul_return_2 - // stack: mul_return_2, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - DUP7 - // stack: scratch_space, mul_return_2, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - DUP3 - // stack: len, scratch_space, mul_return_2, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - %jump(mul_bignum_reduce_helper) -mul_return_2: - // stack: len, n, a_start_loc, bi, output_cur, scratch_space, retdest - - // Add the multiplication result into output_cur = output_len[i]. - PUSH mul_return_3 - // stack: mul_return_3, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - DUP7 - // stack: scratch_space, mul_return_3, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - DUP7 - // stack: output_cur, scratch_space, mul_return_3, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - DUP4 - // stack: len, output_cur, scratch_space, mul_return_3, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - %increment - // stack: len + 1, output_cur, scratch_space, mul_return_3, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - %jump(add_bignum) -mul_return_3: + // stack: output_cur, a_start_loc, b[i], mul_return, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + DUP5 + // stack: len, output_cur, a_start_loc, b[i], mul_return, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + %jump(addmul_bignum) +mul_return: // stack: carry, len, n, a_start_loc, bi, output_cur, scratch_space, retdest DUP6 // stack: output_cur, carry, len, n, a_start_loc, bi, output_cur, scratch_space, retdest diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index f866caad..49d28342 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -210,6 +210,8 @@ fn test_mul_bignum() -> Result<()> { // Run mul function. interpreter.run()?; + dbg!(interpreter.stack()); + // Determine actual product. let new_memory = interpreter.get_kernel_general_memory(); let output_location: usize = output_loc.try_into().unwrap(); From 119eae95fd855ba75e9f935086d6de01ec85f5df Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Mon, 13 Feb 2023 14:09:27 -0800 Subject: [PATCH 04/62] fix --- evm/src/cpu/kernel/asm/bignum/addmul.asm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm/src/cpu/kernel/asm/bignum/addmul.asm b/evm/src/cpu/kernel/asm/bignum/addmul.asm index 742bb829..3ead50c5 100644 --- a/evm/src/cpu/kernel/asm/bignum/addmul.asm +++ b/evm/src/cpu/kernel/asm/bignum/addmul.asm @@ -91,8 +91,8 @@ addmul_loop: // stack: i-1, carry, i-1, a_cur_loc+1, b_cur_loc+1, val, retdest %jumpi(addmul_loop) addmul_end: - // stack: carry_new, i-1, a_cur_loc+1, b_cur_loc+1, retdest - %stack (c, i, a, b) -> (c) + // stack: carry_new, i-1, a_cur_loc+1, b_cur_loc+1, val, retdest + %stack (c, i, a, b, v) -> (c) // stack: carry_new, retdest SWAP1 // stack: retdest, carry_new From 5477c7ddbebbee462785171bf7b2d0681a7e147a Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 15 Feb 2023 11:20:09 -0800 Subject: [PATCH 05/62] fixes --- evm/src/cpu/kernel/asm/bignum/addmul.asm | 20 +++++------ evm/src/cpu/kernel/tests/bignum.rs | 46 ++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/evm/src/cpu/kernel/asm/bignum/addmul.asm b/evm/src/cpu/kernel/asm/bignum/addmul.asm index 3ead50c5..701a2afa 100644 --- a/evm/src/cpu/kernel/asm/bignum/addmul.asm +++ b/evm/src/cpu/kernel/asm/bignum/addmul.asm @@ -50,20 +50,20 @@ addmul_loop: ADD // stack: prod_hi' = prod_hi + prod_lo_carry, prod_lo', carry, i, a_cur_loc, b_cur_loc, val, retdest DUP3 - // stack: carry, prod_lo', prod_hi', carry, i, a_cur_loc, b_cur_loc, val, retdest - DUP2 - // stack: prod_lo', carry, prod_lo', prod_hi', carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: carry, prod_hi', prod_lo', carry, i, a_cur_loc, b_cur_loc, val, retdest + DUP3 + // stack: prod_lo', carry, prod_hi', prod_lo', carry, i, a_cur_loc, b_cur_loc, val, retdest ADD %shl_const(128) %shr_const(128) - // stack: to_write = (prod_lo' + carry) % 2^128, prod_lo', prod_hi', carry, i, a_cur_loc, b_cur_loc, val, retdest - SWAP1 - // stack: prod_lo', to_write, prod_hi', carry, i, a_cur_loc, b_cur_loc, val, retdest - DUP2 - // stack: to_write, prod_lo', to_write, prod_hi', carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: to_write = (prod_lo' + carry) % 2^128, prod_hi', prod_lo', carry, i, a_cur_loc, b_cur_loc, val, retdest + SWAP2 + // stack: prod_lo', prod_hi', to_write, carry, i, a_cur_loc, b_cur_loc, val, retdest + DUP3 + // stack: to_write, prod_lo', prod_hi', to_write, carry, i, a_cur_loc, b_cur_loc, val, retdest LT - // stack: carry_new = to_write < prod_lo', to_write, prod_hi', carry, i, a_cur_loc, b_cur_loc, val, retdest - %stack (cn, tw, ph, c) -> (cn, ph, tw) + // stack: carry_new = to_write < prod_lo', prod_hi', to_write, carry, i, a_cur_loc, b_cur_loc, val, retdest + %stack (vals: 3, c) -> (vals) // stack: carry_new, prod_hi', to_write, i, a_cur_loc, b_cur_loc, val, retdest ADD // stack: carry = carry_new' + prod_hi', to_write, i, a_cur_loc, b_cur_loc, val, retdest diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index 49d28342..6f0edb4c 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -3,6 +3,7 @@ use ethereum_types::U256; use itertools::Itertools; use num::{BigUint, Signed}; use num_bigint::RandBigInt; +use rand::Rng; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; @@ -21,7 +22,7 @@ fn pack_bignums(biguints: &[BigUint], length: usize) -> Vec { fn gen_bignum(bit_size: usize) -> BigUint { let mut rng = rand::thread_rng(); - rng.gen_bigint(bit_size as u64).abs().to_biguint().unwrap() + rng.gen_biguint(bit_size as u64) } fn bignum_len(a: &BigUint) -> usize { @@ -31,8 +32,8 @@ fn bignum_len(a: &BigUint) -> usize { fn gen_two_bignums_ordered(bit_size: usize) -> (BigUint, BigUint) { let mut rng = rand::thread_rng(); let (a, b) = { - let a = rng.gen_bigint(bit_size as u64).abs().to_biguint().unwrap(); - let b = rng.gen_bigint(bit_size as u64).abs().to_biguint().unwrap(); + let a = rng.gen_biguint(bit_size as u64); + let b = rng.gen_biguint(bit_size as u64); (a.clone().max(b.clone()), a.min(b)) }; @@ -176,6 +177,45 @@ fn test_add_bignum() -> Result<()> { Ok(()) } +#[test] +fn test_addmul_bignum() -> Result<()> { + let mut rng = rand::thread_rng(); + let (a, b, length, memory) = prepare_two_bignums(1000); + let val: u64 = 1; + let val_u256 = U256::from(val); + + // Determine expected result. + let result = a + b * BigUint::from(val); + let expected_result: Vec = biguint_to_mem_vec(result); + + let a_start_loc = 0.into(); + let b_start_loc = length; + + // Prepare stack. + let retdest = 0xDEADBEEFu32.into(); + let mut initial_stack: Vec = vec![length, a_start_loc, b_start_loc, val_u256, retdest]; + initial_stack.reverse(); + + // Prepare interpreter. + let addmul_bignum = KERNEL.global_labels["addmul_bignum"]; + let mut interpreter = Interpreter::new_with_kernel(addmul_bignum, initial_stack); + interpreter.set_kernel_general_memory(memory); + + // Run add function. + interpreter.run()?; + + // Determine actual result. + let new_memory = interpreter.get_kernel_general_memory(); + let actual_result: Vec<_> = new_memory[..expected_result.len()].into(); + + dbg!(interpreter.stack()); + + // Compare. + assert_eq!(actual_result, expected_result); + + Ok(()) +} + #[test] fn test_mul_bignum() -> Result<()> { let (a, b, length, memory) = prepare_two_bignums(1000); From efd5e6ec9a28c9807c18265eada1715a57fdea25 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 15 Feb 2023 11:20:48 -0800 Subject: [PATCH 06/62] cleanup --- evm/src/cpu/kernel/tests/bignum.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index 6f0edb4c..7f5b3de4 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -1,9 +1,8 @@ use anyhow::Result; use ethereum_types::U256; use itertools::Itertools; -use num::{BigUint, Signed}; +use num::BigUint; use num_bigint::RandBigInt; -use rand::Rng; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; @@ -179,7 +178,7 @@ fn test_add_bignum() -> Result<()> { #[test] fn test_addmul_bignum() -> Result<()> { - let mut rng = rand::thread_rng(); + let _rng = rand::thread_rng(); let (a, b, length, memory) = prepare_two_bignums(1000); let val: u64 = 1; let val_u256 = U256::from(val); From 10893fe056bc053892afec0a7d06fdb69f95ef48 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 15 Feb 2023 14:50:41 -0800 Subject: [PATCH 07/62] addmul test: use carry --- evm/src/cpu/kernel/asm/bignum/addmul.asm | 2 +- evm/src/cpu/kernel/tests/bignum.rs | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/evm/src/cpu/kernel/asm/bignum/addmul.asm b/evm/src/cpu/kernel/asm/bignum/addmul.asm index 701a2afa..55769bf8 100644 --- a/evm/src/cpu/kernel/asm/bignum/addmul.asm +++ b/evm/src/cpu/kernel/asm/bignum/addmul.asm @@ -1,7 +1,7 @@ // Arithmetic on little-endian integers represented with 128-bit limbs. // All integers must be under a given length bound, and are padded with leading zeroes. -// Sets a[0:len] += b[0:len] * val. +// Sets a[0:len+1] += b[0:len] * val. global addmul_bignum: // stack: len, a_start_loc, b_start_loc, val, retdest PUSH 0 diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index 7f5b3de4..c2b96afa 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -3,6 +3,7 @@ use ethereum_types::U256; use itertools::Itertools; use num::BigUint; use num_bigint::RandBigInt; +use rand::Rng; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; @@ -151,7 +152,7 @@ fn test_add_bignum() -> Result<()> { let expected_sum: Vec = biguint_to_mem_vec(sum); let a_start_loc = 0.into(); - let b_start_loc = length; + let b_start_loc = length ; // Prepare stack. let retdest = 0xDEADBEEFu32.into(); @@ -178,9 +179,12 @@ fn test_add_bignum() -> Result<()> { #[test] fn test_addmul_bignum() -> Result<()> { - let _rng = rand::thread_rng(); - let (a, b, length, memory) = prepare_two_bignums(1000); - let val: u64 = 1; + let mut rng = rand::thread_rng(); + let (a, b, length, mut memory) = prepare_two_bignums(1000); + let len: usize = length.try_into().unwrap(); + memory.splice(len..len, vec![0.into(); 2].iter().cloned()); + + let val: u64 = rng.gen(); let val_u256 = U256::from(val); // Determine expected result. @@ -188,7 +192,7 @@ fn test_addmul_bignum() -> Result<()> { let expected_result: Vec = biguint_to_mem_vec(result); let a_start_loc = 0.into(); - let b_start_loc = length; + let b_start_loc = length + 2; // Prepare stack. let retdest = 0xDEADBEEFu32.into(); @@ -204,7 +208,9 @@ fn test_addmul_bignum() -> Result<()> { interpreter.run()?; // Determine actual result. - let new_memory = interpreter.get_kernel_general_memory(); + let carry = interpreter.stack()[0]; + let mut new_memory = interpreter.get_kernel_general_memory(); + new_memory[len] = carry; let actual_result: Vec<_> = new_memory[..expected_result.len()].into(); dbg!(interpreter.stack()); From af3dc287dfaf44b7d5f558368f90dff0b9530b2b Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 15 Feb 2023 14:50:54 -0800 Subject: [PATCH 08/62] cleanup --- evm/src/cpu/kernel/tests/bignum.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index c2b96afa..38f5ec52 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -213,8 +213,6 @@ fn test_addmul_bignum() -> Result<()> { new_memory[len] = carry; let actual_result: Vec<_> = new_memory[..expected_result.len()].into(); - dbg!(interpreter.stack()); - // Compare. assert_eq!(actual_result, expected_result); From c98bfb0b2c710ac8a292af2251bbce2f7ae1da78 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 15 Feb 2023 14:51:22 -0800 Subject: [PATCH 09/62] cleanup --- evm/src/cpu/kernel/tests/bignum.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index 38f5ec52..72e38ab1 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -152,7 +152,7 @@ fn test_add_bignum() -> Result<()> { let expected_sum: Vec = biguint_to_mem_vec(sum); let a_start_loc = 0.into(); - let b_start_loc = length ; + let b_start_loc = length; // Prepare stack. let retdest = 0xDEADBEEFu32.into(); From 1d7c28ee1d37dfabd623e2d32b73c51c6cf23103 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 16 Feb 2023 11:36:40 -0800 Subject: [PATCH 10/62] bug fixes --- evm/src/cpu/kernel/asm/bignum/addmul.asm | 2 +- evm/src/cpu/kernel/asm/bignum/mul.asm | 96 ++++++++---------------- evm/src/cpu/kernel/tests/bignum.rs | 2 - 3 files changed, 33 insertions(+), 67 deletions(-) diff --git a/evm/src/cpu/kernel/asm/bignum/addmul.asm b/evm/src/cpu/kernel/asm/bignum/addmul.asm index 55769bf8..e1bd3bf2 100644 --- a/evm/src/cpu/kernel/asm/bignum/addmul.asm +++ b/evm/src/cpu/kernel/asm/bignum/addmul.asm @@ -1,7 +1,7 @@ // Arithmetic on little-endian integers represented with 128-bit limbs. // All integers must be under a given length bound, and are padded with leading zeroes. -// Sets a[0:len+1] += b[0:len] * val. +// Sets a[0:len] += b[0:len] * val, and returns the carry. global addmul_bignum: // stack: len, a_start_loc, b_start_loc, val, retdest PUSH 0 diff --git a/evm/src/cpu/kernel/asm/bignum/mul.asm b/evm/src/cpu/kernel/asm/bignum/mul.asm index 1b947c23..d62ce907 100644 --- a/evm/src/cpu/kernel/asm/bignum/mul.asm +++ b/evm/src/cpu/kernel/asm/bignum/mul.asm @@ -3,83 +3,51 @@ // Stores a * b in output_loc, leaving a and b unchanged. // Both a and b have length len; a * b will have length 2 * len. -// Both output_loc and scratch_space must be initialized as zeroes (2 * len of them in the case -// of output_loc, and len + 1 of them in the case of scratch_space). +// output_loc must be initialized as 2 * len zeroes. global mul_bignum: - // stack: len, a_start_loc, b_start_loc, output_loc, scratch_space, retdest + // stack: len, a_start_loc, b_start_loc, output_loc, retdest DUP1 - // stack: len, n=len, a_start_loc, bi=b_start_loc, output_cur=output_loc, scratch_space, retdest + // stack: n=len, len, a_start_loc, bi=b_start_loc, output_cur=output_loc, retdest mul_loop: - // stack: len, n, a_start_loc, bi, output_cur, scratch_space, retdest - - // Copy a from a_start_loc into scratch_space. - DUP1 - // stack: len, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - DUP4 - // stack: a_start_loc, len, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - DUP8 - // stack: scratch_space, a_start_loc, len, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - %memcpy_kernel_general - // stack: len, n, a_start_loc, bi, output_cur, scratch_space, retdest - - // Insert a zero into scratch_space[len]. - DUP6 - // stack: scratch_space, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - DUP2 - // stack: len, scratch_space, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - ADD - // stack: scratch_space + len, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - PUSH 0 - SWAP1 - // stack: scratch_space + len, 0, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - %mstore_kernel_general - // stack: len, n, a_start_loc, bi, output_cur, scratch_space, retdest - - // Multiply a by b[i] and add into output_cur. + // stack: n, len, a_start_loc, bi, output_cur, retdest PUSH mul_return - // stack: mul_return, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + // stack: mul_return, n, len, a_start_loc, bi, output_cur, retdest DUP5 - // stack: bi, mul_return, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + // stack: bi, mul_return, n, len, a_start_loc, bi, output_cur, retdest %mload_kernel_general - // stack: b[i], mul_return, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + // stack: b[i], mul_return, n, len, a_start_loc, bi, output_cur, retdest, b DUP5 - // stack: a_start_loc, b[i], mul_return, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + // stack: a_start_loc, b[i], mul_return, n, len, a_start_loc, bi, output_cur, retdest, b DUP8 - // stack: output_cur, a_start_loc, b[i], mul_return, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - DUP5 - // stack: len, output_cur, a_start_loc, b[i], mul_return, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + // stack: output_loc, a_start_loc, b[i], mul_return, n, len, a_start_loc, bi, output_cur, retdest, b + DUP6 + // stack: len, output_loc, a_start_loc, b[i], mul_return, n, len, a_start_loc, bi, output_cur, retdest, b %jump(addmul_bignum) mul_return: - // stack: carry, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + // stack: carry, n, len, a_start_loc, bi, output_cur, retdest DUP6 - // stack: output_cur, carry, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - DUP3 - // stack: len, output_cur, carry, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + // stack: output_cur, carry, n, len, a_start_loc, bi, output_cur, retdest + DUP4 + // stack: len, output_cur, carry, n, len, a_start_loc, bi, output_cur, retdest ADD - // stack: output_cur + len, carry, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - %increment - // stack: output_cur + len + 1, carry, len, n, a_start_loc, bi, output_cur, scratch_space, retdest + // stack: output_cur + len, carry, n, len, a_start_loc, bi, output_cur, retdest %mstore_kernel_general - // stack: len, n, a_start_loc, bi, output_cur, scratch_space, retdest - - // Increment output_cur and b[i], decrement n, and check if we're done. - DUP5 - // stack: output_cur, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - %increment - // stack: output_cur+1, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - DUP5 - %increment - // stack: bi+1, output_cur+1, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - DUP5 - // stack: a_start_loc, bi+1, output_cur+1, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - DUP5 + // stack: n, len, a_start_loc, bi, output_cur, retdest %decrement - // stack: n-1, a_start_loc, bi+1, output_cur+1, len, n, a_start_loc, bi, output_cur, scratch_space, retdest - %stack (new: 4, len, old: 4) -> (len, new) - // stack: len, n-1, a_start_loc, bi+1, output_cur+1, scratch_space, retdest - DUP2 - // stack: n-1, len, n-1, a_start_loc, bi+1, output_cur+1, scratch_space, retdest + // 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 + SWAP4 + %increment + SWAP4 + // stack: n-1, 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 %jumpi(mul_loop) - // stack: len, n, a_start_loc, bi, output_cur, scratch_space, retdest - %pop6 +mul_end: + // stack: n-1, len, a_start_loc, bi+1, output_cur+1, retdest + %pop5 + // stack: retdest JUMP diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index 72e38ab1..0b0cfe2f 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -231,7 +231,6 @@ fn test_mul_bignum() -> Result<()> { let a_start_loc = 0.into(); let b_start_loc = length; let output_loc = length * 2; - let scratch_space = length * 4; // Prepare stack. let retdest = 0xDEADBEEFu32.into(); @@ -240,7 +239,6 @@ fn test_mul_bignum() -> Result<()> { a_start_loc, b_start_loc, output_loc, - scratch_space, retdest, ]; initial_stack.reverse(); From 2aff3e10da59051327a1345656552be7d468c9dc Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 16 Feb 2023 11:37:43 -0800 Subject: [PATCH 11/62] cleanup --- evm/src/cpu/kernel/tests/bignum.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index 0b0cfe2f..544c7ec5 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -234,13 +234,7 @@ fn test_mul_bignum() -> Result<()> { // Prepare stack. let retdest = 0xDEADBEEFu32.into(); - let mut initial_stack: Vec = vec![ - length, - a_start_loc, - b_start_loc, - output_loc, - retdest, - ]; + let mut initial_stack: Vec = vec![length, a_start_loc, b_start_loc, output_loc, retdest]; initial_stack.reverse(); // Prepare interpreter. @@ -251,8 +245,6 @@ fn test_mul_bignum() -> Result<()> { // Run mul function. interpreter.run()?; - dbg!(interpreter.stack()); - // Determine actual product. let new_memory = interpreter.get_kernel_general_memory(); let output_location: usize = output_loc.try_into().unwrap(); From f46694e74d86f51ab006b208efe5106815e004b4 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 16 Feb 2023 11:52:04 -0800 Subject: [PATCH 12/62] more thorough tests --- evm/src/cpu/kernel/tests/bignum.rs | 148 ++++++++++++++++++++++++----- 1 file changed, 126 insertions(+), 22 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index 544c7ec5..17dc5dda 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -1,7 +1,7 @@ use anyhow::Result; use ethereum_types::U256; use itertools::Itertools; -use num::BigUint; +use num::{BigUint, Zero, One}; use num_bigint::RandBigInt; use rand::Rng; @@ -40,7 +40,7 @@ fn gen_two_bignums_ordered(bit_size: usize) -> (BigUint, BigUint) { (a, b) } -fn prepare_bignum(bit_size: usize) -> (BigUint, U256, Vec) { +fn prepare_bignum_random(bit_size: usize) -> (BigUint, U256, Vec) { let a = gen_bignum(bit_size); let length: U256 = bignum_len(&a).into(); let a_limbs = biguint_to_mem_vec(a.clone()); @@ -48,7 +48,23 @@ fn prepare_bignum(bit_size: usize) -> (BigUint, U256, Vec) { (a, length, a_limbs) } -fn prepare_two_bignums(bit_size: usize) -> (BigUint, BigUint, U256, Vec) { +fn prepare_bignum_max(bit_size: usize) -> (BigUint, U256, Vec) { + let a = BigUint::one() << bit_size - 1; + let length: U256 = bignum_len(&a).into(); + let a_limbs = biguint_to_mem_vec(a.clone()); + + (a, length, a_limbs) +} + +fn prepare_bignum_min(bit_size: usize) -> (BigUint, U256, Vec) { + let a = BigUint::zero(); + let length: U256 = bignum_len(&a).into(); + let a_limbs = biguint_to_mem_vec(a.clone()); + + (a, length, a_limbs) +} + +fn prepare_two_bignums_random(bit_size: usize) -> (BigUint, BigUint, U256, Vec) { let (a, b) = gen_two_bignums_ordered(bit_size); let length: U256 = bignum_len(&a).into(); let memory = pack_bignums(&[a.clone(), b.clone()], length.try_into().unwrap()); @@ -56,9 +72,37 @@ fn prepare_two_bignums(bit_size: usize) -> (BigUint, BigUint, U256, Vec) { (a, b, length, memory) } -#[test] -fn test_shr_bignum() -> Result<()> { - let (a, length, memory) = prepare_bignum(1000); +fn prepare_two_bignums_max(bit_size: usize) -> (BigUint, BigUint, U256, Vec) { + let a = BigUint::one() << bit_size - 1; + let b = BigUint::one() << bit_size - 2; + let length: U256 = bignum_len(&a).into(); + let memory = pack_bignums(&[a.clone(), b.clone()], length.try_into().unwrap()); + + (a, b, length, memory) +} + +fn prepare_two_bignums_min(bit_size: usize) -> (BigUint, BigUint, U256, Vec) { + let a = BigUint::one(); + let b = BigUint::zero(); + let length: U256 = bignum_len(&a).into(); + let memory = pack_bignums(&[a.clone(), b.clone()], length.try_into().unwrap()); + + (a, b, length, memory) +} + +fn prepare_two_bignums_diff(bit_size: usize) -> (BigUint, BigUint, U256, Vec) { + let a = BigUint::one() << bit_size - 1; + let b = BigUint::zero(); + let length: U256 = bignum_len(&a).into(); + let memory = pack_bignums(&[a.clone(), b.clone()], length.try_into().unwrap()); + + (a, b, length, memory) +} + +fn test_shr_bignum(prepare_bignum_fn: &F) -> Result<()> +where F: Fn(usize) -> (BigUint, U256, Vec) { + + let (a, length, memory) = prepare_bignum_fn(1000); let halved = a >> 1; @@ -80,9 +124,15 @@ fn test_shr_bignum() -> Result<()> { Ok(()) } -#[test] -fn test_iszero_bignum() -> Result<()> { - let (_a, length, memory) = prepare_bignum(1000); +fn test_iszero_bignum(prepare_bignum_fn: &F) -> Result<()> +where F: Fn(usize) -> (BigUint, U256, Vec) { + let (a, length, memory) = { + let (a, length, memory) = prepare_bignum_fn(1000); + while a == BigUint::zero() { + (a, length, memory) = prepare_bignum_fn(1000); + } + (a, length, memory) + }; let retdest = 0xDEADBEEFu32.into(); let iszero_bignum = KERNEL.global_labels["iszero_bignum"]; @@ -112,9 +162,9 @@ fn test_iszero_bignum() -> Result<()> { Ok(()) } -#[test] -fn test_ge_bignum() -> Result<()> { - let (_a, _b, length, memory) = prepare_two_bignums(1000); +fn test_ge_bignum(prepare_two_bignums_fn: &F) -> Result<()> +where F: Fn(usize) -> (BigUint, BigUint, U256, Vec) { + let (_a, _b, length, memory) = prepare_two_bignums_fn(1000); let retdest = 0xDEADBEEFu32.into(); let ge_bignum = KERNEL.global_labels["ge_bignum"]; @@ -143,9 +193,9 @@ fn test_ge_bignum() -> Result<()> { Ok(()) } -#[test] -fn test_add_bignum() -> Result<()> { - let (a, b, length, memory) = prepare_two_bignums(1000); +fn test_add_bignum(prepare_two_bignums_fn: &F) -> Result<()> +where F: Fn(usize) -> (BigUint, BigUint, U256, Vec) { + let (a, b, length, memory) = prepare_two_bignums_fn(1000); // Determine expected sum. let sum = a + b; @@ -177,14 +227,14 @@ fn test_add_bignum() -> Result<()> { Ok(()) } -#[test] -fn test_addmul_bignum() -> Result<()> { +fn test_addmul_bignum(prepare_two_bignums_fn: &F) -> Result<()> +where F: Fn(usize) -> (BigUint, BigUint, U256, Vec) { let mut rng = rand::thread_rng(); - let (a, b, length, mut memory) = prepare_two_bignums(1000); + let (a, b, length, mut memory) = prepare_two_bignums_fn(1000); let len: usize = length.try_into().unwrap(); memory.splice(len..len, vec![0.into(); 2].iter().cloned()); - let val: u64 = rng.gen(); + let val: u128 = rng.gen(); let val_u256 = U256::from(val); // Determine expected result. @@ -219,9 +269,9 @@ fn test_addmul_bignum() -> Result<()> { Ok(()) } -#[test] -fn test_mul_bignum() -> Result<()> { - let (a, b, length, memory) = prepare_two_bignums(1000); +fn test_mul_bignum(prepare_bignum_fn: &F) -> Result<()> +where F: Fn(usize) -> (BigUint, U256, Vec) { + let (a, b, length, memory) = prepare_two_bignums_fn(1000); // Determine expected product. let product = a * b; @@ -255,3 +305,57 @@ fn test_mul_bignum() -> Result<()> { Ok(()) } + +#[test] +fn test_shr_bignum_all() -> Result<()> { + test_shr_bignum(&prepare_bignum_random)?; + test_shr_bignum(&prepare_bignum_max)?; + test_shr_bignum(&prepare_bignum_min)?; + + Ok(()) +} + +#[test] +fn test_iszero_bignum_all() -> Result<()> { + test_iszero_bignum(&prepare_bignum_random)?; + test_iszero_bignum(&prepare_bignum_max)?; + // No need to test for min, since it is zero. + + Ok(()) +} + +#[test] +fn test_ge_bignum_all() -> Result<()> { + test_ge_bignum(&prepare_bignum_random)?; + test_ge_bignum(&prepare_bignum_max)?; + test_ge_bignum(&prepare_bignum_min)?; + + Ok(()) +} + +#[test] +fn test_add_bignum_all() -> Result<()> { + test_add_bignum(&prepare_two_bignums_random)?; + test_add_bignum(&prepare_two_bignums_max)?; + test_add_bignum(&prepare_two_bignums_min)?; + + Ok(()) +} + +#[test] +fn test_addmul_bignum_all() -> Result<()> { + test_addmul_bignum(&prepare_two_bignums_random)?; + test_addmul_bignum(&prepare_two_bignums_max)?; + test_addmul_bignum(&prepare_two_bignums_min)?; + + Ok(()) +} + +#[test] +fn test_mul_bignum_all() -> Result<()> { + test_mul_bignum(&prepare_bignum_random)?; + test_mul_bignum(&prepare_bignum_max)?; + test_mul_bignum(&prepare_bignum_min)?; + + Ok(()) +} From 0fdd93b8ce1a3559aa9fa740bcbfaa0e87c96682 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 16 Feb 2023 11:54:18 -0800 Subject: [PATCH 13/62] cleanup --- evm/src/cpu/kernel/tests/bignum.rs | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index 17dc5dda..12e8b357 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -1,7 +1,7 @@ use anyhow::Result; use ethereum_types::U256; use itertools::Itertools; -use num::{BigUint, Zero, One}; +use num::{BigUint, One, Zero}; use num_bigint::RandBigInt; use rand::Rng; @@ -100,8 +100,9 @@ fn prepare_two_bignums_diff(bit_size: usize) -> (BigUint, BigUint, U256, Vec(prepare_bignum_fn: &F) -> Result<()> -where F: Fn(usize) -> (BigUint, U256, Vec) { - +where + F: Fn(usize) -> (BigUint, U256, Vec), +{ let (a, length, memory) = prepare_bignum_fn(1000); let halved = a >> 1; @@ -125,7 +126,9 @@ where F: Fn(usize) -> (BigUint, U256, Vec) { } fn test_iszero_bignum(prepare_bignum_fn: &F) -> Result<()> -where F: Fn(usize) -> (BigUint, U256, Vec) { +where + F: Fn(usize) -> (BigUint, U256, Vec), +{ let (a, length, memory) = { let (a, length, memory) = prepare_bignum_fn(1000); while a == BigUint::zero() { @@ -163,7 +166,9 @@ where F: Fn(usize) -> (BigUint, U256, Vec) { } fn test_ge_bignum(prepare_two_bignums_fn: &F) -> Result<()> -where F: Fn(usize) -> (BigUint, BigUint, U256, Vec) { +where + F: Fn(usize) -> (BigUint, BigUint, U256, Vec), +{ let (_a, _b, length, memory) = prepare_two_bignums_fn(1000); let retdest = 0xDEADBEEFu32.into(); @@ -194,7 +199,9 @@ where F: Fn(usize) -> (BigUint, BigUint, U256, Vec) { } fn test_add_bignum(prepare_two_bignums_fn: &F) -> Result<()> -where F: Fn(usize) -> (BigUint, BigUint, U256, Vec) { +where + F: Fn(usize) -> (BigUint, BigUint, U256, Vec), +{ let (a, b, length, memory) = prepare_two_bignums_fn(1000); // Determine expected sum. @@ -228,7 +235,9 @@ where F: Fn(usize) -> (BigUint, BigUint, U256, Vec) { } fn test_addmul_bignum(prepare_two_bignums_fn: &F) -> Result<()> -where F: Fn(usize) -> (BigUint, BigUint, U256, Vec) { +where + F: Fn(usize) -> (BigUint, BigUint, U256, Vec), +{ let mut rng = rand::thread_rng(); let (a, b, length, mut memory) = prepare_two_bignums_fn(1000); let len: usize = length.try_into().unwrap(); @@ -270,7 +279,9 @@ where F: Fn(usize) -> (BigUint, BigUint, U256, Vec) { } fn test_mul_bignum(prepare_bignum_fn: &F) -> Result<()> -where F: Fn(usize) -> (BigUint, U256, Vec) { +where + F: Fn(usize) -> (BigUint, U256, Vec), +{ let (a, b, length, memory) = prepare_two_bignums_fn(1000); // Determine expected product. From 4f41218229aa342b957c59a23bb7e793e4c5ff6e Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 16 Feb 2023 11:54:27 -0800 Subject: [PATCH 14/62] cleanup --- evm/src/cpu/kernel/tests/bignum.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index 12e8b357..d5735baf 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -337,9 +337,9 @@ fn test_iszero_bignum_all() -> Result<()> { #[test] fn test_ge_bignum_all() -> Result<()> { - test_ge_bignum(&prepare_bignum_random)?; - test_ge_bignum(&prepare_bignum_max)?; - test_ge_bignum(&prepare_bignum_min)?; + test_ge_bignum(&prepare_two_bignums_random)?; + test_ge_bignum(&prepare_two_bignums_max)?; + test_ge_bignum(&prepare_two_bignums_min)?; Ok(()) } From 1100445d9cdc2efb161eba40cc10f6b9e7036d85 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 16 Feb 2023 11:55:00 -0800 Subject: [PATCH 15/62] cleanup --- evm/src/cpu/kernel/tests/bignum.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index d5735baf..b108ade8 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -278,9 +278,9 @@ where Ok(()) } -fn test_mul_bignum(prepare_bignum_fn: &F) -> Result<()> +fn test_mul_bignum(prepare_two_bignums_fn: &F: &F) -> Result<()> where - F: Fn(usize) -> (BigUint, U256, Vec), + F: Fn(usize) -> (BigUint, BigUint, U256, Vec), { let (a, b, length, memory) = prepare_two_bignums_fn(1000); From 3662e41df7b7ab966ecceecc6933663d59047e6c Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 16 Feb 2023 11:55:12 -0800 Subject: [PATCH 16/62] fixes --- evm/src/cpu/kernel/tests/bignum.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index b108ade8..e71fac87 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -278,7 +278,7 @@ where Ok(()) } -fn test_mul_bignum(prepare_two_bignums_fn: &F: &F) -> Result<()> +fn test_mul_bignum(prepare_two_bignums_fn: &F) -> Result<()> where F: Fn(usize) -> (BigUint, BigUint, U256, Vec), { From 3a019f99af98de287c8799bd097c2bd7e94b6fa3 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 16 Feb 2023 11:55:44 -0800 Subject: [PATCH 17/62] fix --- evm/src/cpu/kernel/tests/bignum.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index e71fac87..28d43739 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -364,9 +364,9 @@ fn test_addmul_bignum_all() -> Result<()> { #[test] fn test_mul_bignum_all() -> Result<()> { - test_mul_bignum(&prepare_bignum_random)?; - test_mul_bignum(&prepare_bignum_max)?; - test_mul_bignum(&prepare_bignum_min)?; + test_mul_bignum(&prepare_two_bignums_random)?; + test_mul_bignum(&prepare_two_bignums_max)?; + test_mul_bignum(&prepare_two_bignums_min)?; Ok(()) } From bac38f8276e41d579455fac6d69b531e9a037bf3 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 16 Feb 2023 11:56:54 -0800 Subject: [PATCH 18/62] fix --- evm/src/cpu/kernel/tests/bignum.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index 28d43739..b6be9a70 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -129,12 +129,12 @@ fn test_iszero_bignum(prepare_bignum_fn: &F) -> Result<()> where F: Fn(usize) -> (BigUint, U256, Vec), { - let (a, length, memory) = { - let (a, length, memory) = prepare_bignum_fn(1000); + let (length, memory) = { + let (mut a, mut length, mut memory) = prepare_bignum_fn(1000); while a == BigUint::zero() { (a, length, memory) = prepare_bignum_fn(1000); } - (a, length, memory) + (length, memory) }; let retdest = 0xDEADBEEFu32.into(); From f2538fff418b83f6b4788521fffffce950c9d282 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 16 Feb 2023 12:23:54 -0800 Subject: [PATCH 19/62] cleanup --- evm/src/cpu/kernel/tests/bignum.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index b6be9a70..cdb71f22 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -49,14 +49,14 @@ fn prepare_bignum_random(bit_size: usize) -> (BigUint, U256, Vec) { } fn prepare_bignum_max(bit_size: usize) -> (BigUint, U256, Vec) { - let a = BigUint::one() << bit_size - 1; + let a = BigUint::one() << (bit_size - 1); let length: U256 = bignum_len(&a).into(); let a_limbs = biguint_to_mem_vec(a.clone()); (a, length, a_limbs) } -fn prepare_bignum_min(bit_size: usize) -> (BigUint, U256, Vec) { +fn prepare_bignum_min(_bit_size: usize) -> (BigUint, U256, Vec) { let a = BigUint::zero(); let length: U256 = bignum_len(&a).into(); let a_limbs = biguint_to_mem_vec(a.clone()); @@ -73,15 +73,15 @@ fn prepare_two_bignums_random(bit_size: usize) -> (BigUint, BigUint, U256, Vec (BigUint, BigUint, U256, Vec) { - let a = BigUint::one() << bit_size - 1; - let b = BigUint::one() << bit_size - 2; + let a = BigUint::one() << (bit_size - 1); + let b = BigUint::one() << (bit_size - 2); let length: U256 = bignum_len(&a).into(); let memory = pack_bignums(&[a.clone(), b.clone()], length.try_into().unwrap()); (a, b, length, memory) } -fn prepare_two_bignums_min(bit_size: usize) -> (BigUint, BigUint, U256, Vec) { +fn prepare_two_bignums_min(_bit_size: usize) -> (BigUint, BigUint, U256, Vec) { let a = BigUint::one(); let b = BigUint::zero(); let length: U256 = bignum_len(&a).into(); @@ -91,7 +91,7 @@ fn prepare_two_bignums_min(bit_size: usize) -> (BigUint, BigUint, U256, Vec (BigUint, BigUint, U256, Vec) { - let a = BigUint::one() << bit_size - 1; + let a = BigUint::one() << (bit_size - 1); let b = BigUint::zero(); let length: U256 = bignum_len(&a).into(); let memory = pack_bignums(&[a.clone(), b.clone()], length.try_into().unwrap()); From 6d997a6566eb14111ebe7ebc81a1b9371eff8db3 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 16 Feb 2023 13:49:16 -0800 Subject: [PATCH 20/62] more tests --- evm/src/cpu/kernel/tests/bignum.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index cdb71f22..ff92ac50 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -340,6 +340,7 @@ fn test_ge_bignum_all() -> Result<()> { test_ge_bignum(&prepare_two_bignums_random)?; test_ge_bignum(&prepare_two_bignums_max)?; test_ge_bignum(&prepare_two_bignums_min)?; + test_ge_bignum(&prepare_two_bignums_diff)?; Ok(()) } @@ -349,6 +350,7 @@ fn test_add_bignum_all() -> Result<()> { test_add_bignum(&prepare_two_bignums_random)?; test_add_bignum(&prepare_two_bignums_max)?; test_add_bignum(&prepare_two_bignums_min)?; + test_add_bignum(&prepare_two_bignums_diff)?; Ok(()) } @@ -358,6 +360,7 @@ fn test_addmul_bignum_all() -> Result<()> { test_addmul_bignum(&prepare_two_bignums_random)?; test_addmul_bignum(&prepare_two_bignums_max)?; test_addmul_bignum(&prepare_two_bignums_min)?; + test_addmul_bignum(&prepare_two_bignums_diff)?; Ok(()) } @@ -367,6 +370,7 @@ fn test_mul_bignum_all() -> Result<()> { test_mul_bignum(&prepare_two_bignums_random)?; test_mul_bignum(&prepare_two_bignums_max)?; test_mul_bignum(&prepare_two_bignums_min)?; + test_mul_bignum(&prepare_two_bignums_diff)?; Ok(()) } From 9e7dc7ca79c2c4517f21694dab9cbbe4face5507 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 14 Mar 2023 12:18:16 -0700 Subject: [PATCH 21/62] addressed comments --- evm/src/cpu/kernel/asm/bignum/ge.asm | 3 ++- evm/src/cpu/kernel/asm/bignum/iszero.asm | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/asm/bignum/ge.asm b/evm/src/cpu/kernel/asm/bignum/ge.asm index cdd7712f..e7f5aca2 100644 --- a/evm/src/cpu/kernel/asm/bignum/ge.asm +++ b/evm/src/cpu/kernel/asm/bignum/ge.asm @@ -1,7 +1,8 @@ // Arithmetic on little-endian integers represented with 128-bit limbs. // All integers must be under a given length bound, and are padded with leading zeroes. -// Returns a >= b. +// Compares two bignums of the same given length. Assumes that len > 0. +// Returns 1 if a > b, 3 if a == b, and 0 if a < b. global ge_bignum: // stack: len, a_start_loc, b_start_loc, retdest SWAP1 diff --git a/evm/src/cpu/kernel/asm/bignum/iszero.asm b/evm/src/cpu/kernel/asm/bignum/iszero.asm index ff755270..2f742f77 100644 --- a/evm/src/cpu/kernel/asm/bignum/iszero.asm +++ b/evm/src/cpu/kernel/asm/bignum/iszero.asm @@ -3,6 +3,10 @@ global iszero_bignum: // stack: len, start_loc, retdest + DUP1 + // stack: len, len, start_loc, retdest + ISZERO + %jumpi(eqzero) DUP2 // stack: start_loc, len, start_loc, retdest ADD From 04f44ef4da1a5781c5da6b6a170de95e288adaf2 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 14 Mar 2023 12:19:13 -0700 Subject: [PATCH 22/62] addressed comments --- evm/src/cpu/kernel/asm/bignum/add.asm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/asm/bignum/add.asm b/evm/src/cpu/kernel/asm/bignum/add.asm index d38c9701..038c7675 100644 --- a/evm/src/cpu/kernel/asm/bignum/add.asm +++ b/evm/src/cpu/kernel/asm/bignum/add.asm @@ -1,7 +1,8 @@ // Arithmetic on little-endian integers represented with 128-bit limbs. // All integers must be under a given length bound, and are padded with leading zeroes. -// Replaces a with a + b, leaving b unchanged. +// Adds two bignums of the same given length. Assumes that len > 0. +// Replaces a with a + b, leaving b unchanged, and returns the final carry. global add_bignum: // stack: len, a_start_loc, b_start_loc, retdest PUSH 0 From 87ad5714aa8938633a7e210c5fa4308296bcb87c Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 14 Mar 2023 12:20:38 -0700 Subject: [PATCH 23/62] addressed comments --- evm/src/cpu/kernel/asm/bignum/shr.asm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/asm/bignum/shr.asm b/evm/src/cpu/kernel/asm/bignum/shr.asm index 69d32b07..5e3a56ef 100644 --- a/evm/src/cpu/kernel/asm/bignum/shr.asm +++ b/evm/src/cpu/kernel/asm/bignum/shr.asm @@ -2,6 +2,7 @@ // All integers must be under a given length bound, and are padded with leading zeroes. // Shifts a given bignum right by one bit (in place). +// Assumes that len > 0. global shr_bignum: // stack: len, start_loc, retdest DUP2 @@ -30,7 +31,7 @@ shr_loop: // stack: carry, a[i] >> 1, i, new_carry, start_loc, retdest %shl_const(127) // stack: carry << 127, a[i] >> 1, i, new_carry, start_loc, retdest - OR + ADD // stack: carry << 127 | a[i] >> 1, i, new_carry, start_loc, retdest DUP2 // stack: i, carry << 127 | a[i] >> 1, i, new_carry, start_loc, retdest From 2000d308f86ad32448ab99b70ef72f3ea5d1ef11 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 14 Mar 2023 14:03:59 -0700 Subject: [PATCH 24/62] addressed comments --- evm/src/cpu/kernel/tests/bignum.rs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index ff92ac50..eb1726db 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -3,12 +3,15 @@ use ethereum_types::U256; use itertools::Itertools; use num::{BigUint, One, Zero}; use num_bigint::RandBigInt; +use plonky2_util::ceil_div_usize; use rand::Rng; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; use crate::util::{biguint_to_mem_vec, mem_vec_to_biguint}; +const BIGNUM_LIMB_BITS: usize = 128; + fn pack_bignums(biguints: &[BigUint], length: usize) -> Vec { biguints .iter() @@ -26,18 +29,13 @@ fn gen_bignum(bit_size: usize) -> BigUint { } fn bignum_len(a: &BigUint) -> usize { - (a.bits() as usize) / 128 + 1 + a.bits() as usize / BIGNUM_LIMB_BITS + 1 } fn gen_two_bignums_ordered(bit_size: usize) -> (BigUint, BigUint) { let mut rng = rand::thread_rng(); - let (a, b) = { - let a = rng.gen_biguint(bit_size as u64); - let b = rng.gen_biguint(bit_size as u64); - (a.clone().max(b.clone()), a.min(b)) - }; - - (a, b) + let (a, b) = (rng.gen_biguint(bit_size as u64), rng.gen_biguint(bit_size as u64)); + if b < a { (a, b) } else { (b, a) } } fn prepare_bignum_random(bit_size: usize) -> (BigUint, U256, Vec) { @@ -49,7 +47,7 @@ fn prepare_bignum_random(bit_size: usize) -> (BigUint, U256, Vec) { } fn prepare_bignum_max(bit_size: usize) -> (BigUint, U256, Vec) { - let a = BigUint::one() << (bit_size - 1); + let a = (BigUint::one() << bit_size) - BigUint::one(); let length: U256 = bignum_len(&a).into(); let a_limbs = biguint_to_mem_vec(a.clone()); @@ -73,8 +71,8 @@ fn prepare_two_bignums_random(bit_size: usize) -> (BigUint, BigUint, U256, Vec (BigUint, BigUint, U256, Vec) { - let a = BigUint::one() << (bit_size - 1); - let b = BigUint::one() << (bit_size - 2); + let a = (BigUint::one() << bit_size) - BigUint::one(); + let b = (BigUint::one() << bit_size) - BigUint::from(2u8); let length: U256 = bignum_len(&a).into(); let memory = pack_bignums(&[a.clone(), b.clone()], length.try_into().unwrap()); From c4b511baf457933adc315a7ebad3a0c2e0fa3e2a Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 14 Mar 2023 14:28:21 -0700 Subject: [PATCH 25/62] addressed comments --- evm/src/cpu/kernel/asm/bignum/shr.asm | 10 ++++++++++ evm/src/cpu/kernel/interpreter.rs | 4 +++- evm/src/cpu/kernel/tests/bignum.rs | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/evm/src/cpu/kernel/asm/bignum/shr.asm b/evm/src/cpu/kernel/asm/bignum/shr.asm index 5e3a56ef..399b372e 100644 --- a/evm/src/cpu/kernel/asm/bignum/shr.asm +++ b/evm/src/cpu/kernel/asm/bignum/shr.asm @@ -4,6 +4,11 @@ // Shifts a given bignum right by one bit (in place). // Assumes that len > 0. global shr_bignum: + // stack: len, start_loc, retdest + DUP1 + // stack: len, len, start_loc, retdest + ISZERO + %jumpi(shr_end_len_zero) // stack: len, start_loc, retdest DUP2 // stack: start_loc, len, start_loc, retdest @@ -55,3 +60,8 @@ shr_end: %pop3 // stack: retdest JUMP +shr_end_len_zero: + // stack: len, start_loc, retdest + %pop2 + // stack: retdest + JUMP diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index b0d3a784..d856bc2b 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -770,7 +770,9 @@ impl<'a> Interpreter<'a> { fn run_mload_general(&mut self) { let context = self.pop().as_usize(); let segment = Segment::all()[self.pop().as_usize()]; - let offset = self.pop().as_usize(); + let x = self.pop(); + dbg!(x); + let offset = x.as_usize(); let value = self .generation_state .memory diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index eb1726db..ce030b54 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -29,7 +29,7 @@ fn gen_bignum(bit_size: usize) -> BigUint { } fn bignum_len(a: &BigUint) -> usize { - a.bits() as usize / BIGNUM_LIMB_BITS + 1 + ceil_div_usize(a.bits() as usize, BIGNUM_LIMB_BITS) } fn gen_two_bignums_ordered(bit_size: usize) -> (BigUint, BigUint) { From 4a76255341358ce6e03646c2ac3a0ded343beb03 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 14 Mar 2023 14:37:20 -0700 Subject: [PATCH 26/62] name change --- evm/src/cpu/kernel/tests/bignum.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index ce030b54..704989c6 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -12,7 +12,7 @@ use crate::util::{biguint_to_mem_vec, mem_vec_to_biguint}; const BIGNUM_LIMB_BITS: usize = 128; -fn pack_bignums(biguints: &[BigUint], length: usize) -> Vec { +fn pad_bignums(biguints: &[BigUint], length: usize) -> Vec { biguints .iter() .flat_map(|biguint| { @@ -65,7 +65,7 @@ fn prepare_bignum_min(_bit_size: usize) -> (BigUint, U256, Vec) { fn prepare_two_bignums_random(bit_size: usize) -> (BigUint, BigUint, U256, Vec) { let (a, b) = gen_two_bignums_ordered(bit_size); let length: U256 = bignum_len(&a).into(); - let memory = pack_bignums(&[a.clone(), b.clone()], length.try_into().unwrap()); + let memory = pad_bignums(&[a.clone(), b.clone()], length.try_into().unwrap()); (a, b, length, memory) } @@ -74,7 +74,7 @@ fn prepare_two_bignums_max(bit_size: usize) -> (BigUint, BigUint, U256, Vec (BigUint, BigUint, U256, Vec (BigUint, BigUint, U256, Vec Date: Tue, 14 Mar 2023 14:37:47 -0700 Subject: [PATCH 27/62] cleanup --- evm/src/cpu/kernel/tests/bignum.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index 704989c6..db4faebd 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -34,8 +34,15 @@ fn bignum_len(a: &BigUint) -> usize { fn gen_two_bignums_ordered(bit_size: usize) -> (BigUint, BigUint) { let mut rng = rand::thread_rng(); - let (a, b) = (rng.gen_biguint(bit_size as u64), rng.gen_biguint(bit_size as u64)); - if b < a { (a, b) } else { (b, a) } + let (a, b) = ( + rng.gen_biguint(bit_size as u64), + rng.gen_biguint(bit_size as u64), + ); + if b < a { + (a, b) + } else { + (b, a) + } } fn prepare_bignum_random(bit_size: usize) -> (BigUint, U256, Vec) { From d4c7bfd59262b5b608eb71b09d0217191a489eac Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 14 Mar 2023 15:15:19 -0700 Subject: [PATCH 28/62] addressed comments --- evm/src/cpu/kernel/asm/bignum/mul.asm | 1 + evm/src/cpu/kernel/interpreter.rs | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/evm/src/cpu/kernel/asm/bignum/mul.asm b/evm/src/cpu/kernel/asm/bignum/mul.asm index d62ce907..cc53c3a0 100644 --- a/evm/src/cpu/kernel/asm/bignum/mul.asm +++ b/evm/src/cpu/kernel/asm/bignum/mul.asm @@ -45,6 +45,7 @@ mul_return: // stack: n-1, 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 + STOP %jumpi(mul_loop) mul_end: // stack: n-1, len, a_start_loc, bi+1, output_cur+1, retdest diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index d856bc2b..b0d3a784 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -770,9 +770,7 @@ impl<'a> Interpreter<'a> { fn run_mload_general(&mut self) { let context = self.pop().as_usize(); let segment = Segment::all()[self.pop().as_usize()]; - let x = self.pop(); - dbg!(x); - let offset = x.as_usize(); + let offset = self.pop().as_usize(); let value = self .generation_state .memory From 4b6a51469f7e123f230f888133e62fb7cacf4146 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 14 Mar 2023 15:21:25 -0700 Subject: [PATCH 29/62] fix --- evm/src/cpu/kernel/asm/bignum/mul.asm | 1 - 1 file changed, 1 deletion(-) diff --git a/evm/src/cpu/kernel/asm/bignum/mul.asm b/evm/src/cpu/kernel/asm/bignum/mul.asm index cc53c3a0..d62ce907 100644 --- a/evm/src/cpu/kernel/asm/bignum/mul.asm +++ b/evm/src/cpu/kernel/asm/bignum/mul.asm @@ -45,7 +45,6 @@ mul_return: // stack: n-1, 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 - STOP %jumpi(mul_loop) mul_end: // stack: n-1, len, a_start_loc, bi+1, output_cur+1, retdest From d23e4e20b6a8a253afa13fcf6cd879eb6e42ed8a Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 14 Mar 2023 15:33:36 -0700 Subject: [PATCH 30/62] deal with and test zero-len case --- evm/src/cpu/kernel/asm/bignum/add.asm | 13 +++++++++++++ evm/src/cpu/kernel/asm/bignum/addmul.asm | 12 ++++++++++++ evm/src/cpu/kernel/asm/bignum/mul.asm | 9 +++++++++ evm/src/cpu/kernel/asm/bignum/shr.asm | 4 ++-- evm/src/cpu/kernel/tests/bignum.rs | 12 ++++++++++++ 5 files changed, 48 insertions(+), 2 deletions(-) diff --git a/evm/src/cpu/kernel/asm/bignum/add.asm b/evm/src/cpu/kernel/asm/bignum/add.asm index 038c7675..64293f11 100644 --- a/evm/src/cpu/kernel/asm/bignum/add.asm +++ b/evm/src/cpu/kernel/asm/bignum/add.asm @@ -4,6 +4,11 @@ // Adds two bignums of the same given length. Assumes that len > 0. // Replaces a with a + b, leaving b unchanged, and returns the final carry. global add_bignum: + // stack: len, a_start_loc, b_start_loc, retdest + DUP1 + // stack: len, len, a_start_loc, b_start_loc, retdest + ISZERO + %jumpi(len_zero) // stack: len, a_start_loc, b_start_loc, retdest PUSH 0 // stack: carry=0, i=len, a_cur_loc=a_start_loc, b_cur_loc=b_start_loc, retdest @@ -55,3 +60,11 @@ add_end: SWAP1 // stack: retdest, carry_new JUMP +len_zero: + // stack: len, a_start_loc, b_start_loc, retdest + %pop3 + // stack: retdest + PUSH 0 + // stack: carry=0, retdest + SWAP1 + JUMP \ No newline at end of file diff --git a/evm/src/cpu/kernel/asm/bignum/addmul.asm b/evm/src/cpu/kernel/asm/bignum/addmul.asm index e1bd3bf2..9e4ce2ba 100644 --- a/evm/src/cpu/kernel/asm/bignum/addmul.asm +++ b/evm/src/cpu/kernel/asm/bignum/addmul.asm @@ -4,6 +4,10 @@ // Sets a[0:len] += b[0:len] * val, and returns the carry. global addmul_bignum: // stack: len, a_start_loc, b_start_loc, val, retdest + DUP1 + // stack: len, len, a_start_loc, b_start_loc, val, retdest + ISZERO + %jumpi(len_zero) PUSH 0 // stack: carry=0, i=len, a_cur_loc=a_start_loc, b_cur_loc=b_start_loc, val, retdest addmul_loop: @@ -97,3 +101,11 @@ addmul_end: SWAP1 // stack: retdest, carry_new JUMP +len_zero: + // stack: len, a_start_loc, b_start_loc, val, retdest + %pop4 + // stack: retdest + PUSH 0 + // stack: carry=0, retdest + SWAP1 + JUMP diff --git a/evm/src/cpu/kernel/asm/bignum/mul.asm b/evm/src/cpu/kernel/asm/bignum/mul.asm index d62ce907..cbf6a645 100644 --- a/evm/src/cpu/kernel/asm/bignum/mul.asm +++ b/evm/src/cpu/kernel/asm/bignum/mul.asm @@ -7,6 +7,10 @@ global mul_bignum: // stack: len, a_start_loc, b_start_loc, output_loc, retdest DUP1 + // 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 mul_loop: // stack: n, len, a_start_loc, bi, output_cur, retdest @@ -51,3 +55,8 @@ mul_end: %pop5 // stack: retdest JUMP +len_zero: + // stack: len, a_start_loc, b_start_loc, output_loc, retdest + %pop4 + // stack: retdest + JUMP diff --git a/evm/src/cpu/kernel/asm/bignum/shr.asm b/evm/src/cpu/kernel/asm/bignum/shr.asm index 399b372e..42f5cd3b 100644 --- a/evm/src/cpu/kernel/asm/bignum/shr.asm +++ b/evm/src/cpu/kernel/asm/bignum/shr.asm @@ -8,7 +8,7 @@ global shr_bignum: DUP1 // stack: len, len, start_loc, retdest ISZERO - %jumpi(shr_end_len_zero) + %jumpi(len_zero) // stack: len, start_loc, retdest DUP2 // stack: start_loc, len, start_loc, retdest @@ -60,7 +60,7 @@ shr_end: %pop3 // stack: retdest JUMP -shr_end_len_zero: +len_zero: // stack: len, start_loc, retdest %pop2 // stack: retdest diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index db4faebd..141761ba 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -104,6 +104,15 @@ fn prepare_two_bignums_diff(bit_size: usize) -> (BigUint, BigUint, U256, Vec (BigUint, BigUint, U256, Vec) { + let a = BigUint::zero(); + let b = BigUint::zero(); + let length: U256 = bignum_len(&a).into(); + let memory = pad_bignums(&[a.clone(), b.clone()], length.try_into().unwrap()); + + (a, b, length, memory) +} + fn test_shr_bignum(prepare_bignum_fn: &F) -> Result<()> where F: Fn(usize) -> (BigUint, U256, Vec), @@ -356,6 +365,7 @@ fn test_add_bignum_all() -> Result<()> { test_add_bignum(&prepare_two_bignums_max)?; test_add_bignum(&prepare_two_bignums_min)?; test_add_bignum(&prepare_two_bignums_diff)?; + test_add_bignum(&prepare_two_bignums_zero)?; Ok(()) } @@ -366,6 +376,7 @@ fn test_addmul_bignum_all() -> Result<()> { test_addmul_bignum(&prepare_two_bignums_max)?; test_addmul_bignum(&prepare_two_bignums_min)?; test_addmul_bignum(&prepare_two_bignums_diff)?; + test_addmul_bignum(&prepare_two_bignums_zero)?; Ok(()) } @@ -376,6 +387,7 @@ fn test_mul_bignum_all() -> Result<()> { test_mul_bignum(&prepare_two_bignums_max)?; test_mul_bignum(&prepare_two_bignums_min)?; test_mul_bignum(&prepare_two_bignums_diff)?; + test_mul_bignum(&prepare_two_bignums_zero)?; Ok(()) } From e57358bcbd44e74caa30f28ffcf7d7d2e7863b0a Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 15 Mar 2023 13:28:00 -0700 Subject: [PATCH 31/62] ge -> cmp and returns 0, 1, -1 --- evm/src/cpu/kernel/aggregator.rs | 2 +- .../cpu/kernel/asm/bignum/{ge.asm => cmp.asm} | 12 ++++---- evm/src/cpu/kernel/tests/bignum.rs | 30 ++++++++++++------- 3 files changed, 27 insertions(+), 17 deletions(-) rename evm/src/cpu/kernel/asm/bignum/{ge.asm => cmp.asm} (91%) diff --git a/evm/src/cpu/kernel/aggregator.rs b/evm/src/cpu/kernel/aggregator.rs index b82bacaf..bb861ade 100644 --- a/evm/src/cpu/kernel/aggregator.rs +++ b/evm/src/cpu/kernel/aggregator.rs @@ -15,7 +15,7 @@ pub(crate) fn combined_kernel() -> Kernel { "global jumped_to_1: PANIC", include_str!("asm/bignum/add.asm"), include_str!("asm/bignum/addmul.asm"), - include_str!("asm/bignum/ge.asm"), + include_str!("asm/bignum/cmp.asm"), include_str!("asm/bignum/iszero.asm"), include_str!("asm/bignum/mul.asm"), include_str!("asm/bignum/shr.asm"), diff --git a/evm/src/cpu/kernel/asm/bignum/ge.asm b/evm/src/cpu/kernel/asm/bignum/cmp.asm similarity index 91% rename from evm/src/cpu/kernel/asm/bignum/ge.asm rename to evm/src/cpu/kernel/asm/bignum/cmp.asm index e7f5aca2..ff8fb3e6 100644 --- a/evm/src/cpu/kernel/asm/bignum/ge.asm +++ b/evm/src/cpu/kernel/asm/bignum/cmp.asm @@ -2,8 +2,8 @@ // All integers must be under a given length bound, and are padded with leading zeroes. // Compares two bignums of the same given length. Assumes that len > 0. -// Returns 1 if a > b, 3 if a == b, and 0 if a < b. -global ge_bignum: +// 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 SWAP1 // stack: a_start_loc, len, b_start_loc, retdest @@ -59,8 +59,8 @@ equal: // stack: i, a_i_loc, b_i_loc, retdest %pop3 // stack: retdest - PUSH 3 - // stack: 3, retdest + PUSH 0 + // stack: 0, retdest SWAP1 JUMP greater: @@ -75,7 +75,7 @@ less: // stack: i, a_i_loc, b_i_loc, retdest %pop3 // stack: retdest - PUSH 0 - // stack: 0, retdest + PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + // stack: -1, retdest SWAP1 JUMP diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index 141761ba..9dbcf6b7 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -179,14 +179,14 @@ where Ok(()) } -fn test_ge_bignum(prepare_two_bignums_fn: &F) -> Result<()> +fn test_cmp_bignum(prepare_two_bignums_fn: &F) -> Result<()> where F: Fn(usize) -> (BigUint, BigUint, U256, Vec), { let (_a, _b, length, memory) = prepare_two_bignums_fn(1000); let retdest = 0xDEADBEEFu32.into(); - let ge_bignum = KERNEL.global_labels["ge_bignum"]; + let cmp_bignum = KERNEL.global_labels["cmp_bignum"]; let a_start_loc = 0.into(); let b_start_loc = length; @@ -194,7 +194,7 @@ where // Test with a > b. let mut initial_stack: Vec = vec![length, a_start_loc, b_start_loc, retdest]; initial_stack.reverse(); - let mut interpreter = Interpreter::new_with_kernel(ge_bignum, initial_stack); + let mut interpreter = Interpreter::new_with_kernel(cmp_bignum, initial_stack); interpreter.set_kernel_general_memory(memory.clone()); interpreter.run()?; let result = interpreter.stack()[0]; @@ -203,11 +203,21 @@ where // Swap a and b, to test the less-than case. let mut initial_stack: Vec = vec![length, b_start_loc, a_start_loc, retdest]; initial_stack.reverse(); - let mut interpreter = Interpreter::new_with_kernel(ge_bignum, initial_stack); + let mut interpreter = Interpreter::new_with_kernel(cmp_bignum, initial_stack); + interpreter.set_kernel_general_memory(memory.clone()); + interpreter.run()?; + let result = interpreter.stack()[0]; + let minus_one = ((U256::one() << 255) - 1) * 2 + 1; + assert_eq!(result, minus_one); + + // Test equal case. + let mut initial_stack: Vec = vec![length, a_start_loc, a_start_loc, retdest]; + initial_stack.reverse(); + let mut interpreter = Interpreter::new_with_kernel(cmp_bignum, initial_stack); interpreter.set_kernel_general_memory(memory); interpreter.run()?; let result = interpreter.stack()[0]; - assert_eq!(result, 0.into()); + assert_eq!(result, U256::zero()); Ok(()) } @@ -350,11 +360,11 @@ fn test_iszero_bignum_all() -> Result<()> { } #[test] -fn test_ge_bignum_all() -> Result<()> { - test_ge_bignum(&prepare_two_bignums_random)?; - test_ge_bignum(&prepare_two_bignums_max)?; - test_ge_bignum(&prepare_two_bignums_min)?; - test_ge_bignum(&prepare_two_bignums_diff)?; +fn test_cmp_bignum_all() -> Result<()> { + test_cmp_bignum(&prepare_two_bignums_random)?; + test_cmp_bignum(&prepare_two_bignums_max)?; + test_cmp_bignum(&prepare_two_bignums_min)?; + test_cmp_bignum(&prepare_two_bignums_diff)?; Ok(()) } From 0627633439a369f9dc8bdd54aa8f0365ae93921c Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 15 Mar 2023 13:39:43 -0700 Subject: [PATCH 32/62] carry -> carry_limb --- evm/src/cpu/kernel/asm/bignum/addmul.asm | 90 ++++++++++++------------ evm/src/cpu/kernel/asm/bignum/mul.asm | 24 +++---- evm/src/cpu/kernel/tests/bignum.rs | 4 +- 3 files changed, 59 insertions(+), 59 deletions(-) diff --git a/evm/src/cpu/kernel/asm/bignum/addmul.asm b/evm/src/cpu/kernel/asm/bignum/addmul.asm index 9e4ce2ba..3dbb1cd3 100644 --- a/evm/src/cpu/kernel/asm/bignum/addmul.asm +++ b/evm/src/cpu/kernel/asm/bignum/addmul.asm @@ -1,7 +1,7 @@ // Arithmetic on little-endian integers represented with 128-bit limbs. // All integers must be under a given length bound, and are padded with leading zeroes. -// Sets a[0:len] += b[0:len] * val, and returns the carry. +// Sets a[0:len] += b[0:len] * val, and returns the carry (a limb of up to 128 bits). global addmul_bignum: // stack: len, a_start_loc, b_start_loc, val, retdest DUP1 @@ -9,103 +9,103 @@ global addmul_bignum: ISZERO %jumpi(len_zero) PUSH 0 - // stack: carry=0, i=len, a_cur_loc=a_start_loc, b_cur_loc=b_start_loc, val, retdest + // stack: carry_limb=0, i=len, a_cur_loc=a_start_loc, b_cur_loc=b_start_loc, val, retdest addmul_loop: - // stack: carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: carry_limb, i, a_cur_loc, b_cur_loc, val, retdest DUP4 - // stack: b_cur_loc, carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: b_cur_loc, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest %mload_kernel_general - // stack: b[cur], carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: b[cur], carry_limb, i, a_cur_loc, b_cur_loc, val, retdest DUP6 - // stack: val, b[cur], carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: val, b[cur], carry_limb, i, a_cur_loc, b_cur_loc, val, retdest MUL - // stack: val * b[cur], carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: val * b[cur], carry_limb, i, a_cur_loc, b_cur_loc, val, retdest DUP1 - // stack: val * b[cur], val * b[cur], carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: val * b[cur], val * b[cur], carry_limb, i, a_cur_loc, b_cur_loc, val, retdest %shr_const(128) - // stack: (val * b[cur]) // 2^128, val * b[cur], carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: (val * b[cur]) // 2^128, val * b[cur], carry_limb, i, a_cur_loc, b_cur_loc, val, retdest SWAP1 - // stack: val * b[cur], (val * b[cur]) // 2^128, carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: val * b[cur], (val * b[cur]) // 2^128, carry_limb, 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, 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, i, a_cur_loc, b_cur_loc, val, retdest DUP5 - // stack: a_cur_loc, prod_lo, prod_hi, carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: a_cur_loc, prod_lo, prod_hi, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest %mload_kernel_general - // stack: a[cur], prod_lo, prod_hi, carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: a[cur], prod_lo, prod_hi, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest DUP1 - // stack: a[cur], a[cur], prod_lo, prod_hi, carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: a[cur], a[cur], prod_lo, prod_hi, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest SWAP2 - // stack: prod_lo, a[cur], a[cur], prod_hi, carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: prod_lo, a[cur], a[cur], prod_hi, carry_limb, 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, i, a_cur_loc, b_cur_loc, val, retdest + // stack: prod_lo' = (prod_lo + a[cur]) % 2^128, a[cur], prod_hi, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest DUP1 - // stack: prod_lo', prod_lo', a[cur], prod_hi, carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: prod_lo', prod_lo', a[cur], prod_hi, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest SWAP2 - // stack: a[cur], prod_lo', prod_lo', prod_hi, carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: a[cur], prod_lo', prod_lo', prod_hi, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest GT - // stack: prod_lo_carry = a[cur] > prod_lo', prod_lo', prod_hi, carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: prod_lo_carry_limb = a[cur] > prod_lo', prod_lo', prod_hi, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest SWAP1 - // stack: prod_lo', prod_lo_carry, prod_hi, carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: prod_lo', prod_lo_carry_limb, prod_hi, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest SWAP2 - // stack: prod_hi, prod_lo_carry, prod_lo', carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: prod_hi, prod_lo_carry_limb, prod_lo', carry_limb, i, a_cur_loc, b_cur_loc, val, retdest ADD - // stack: prod_hi' = prod_hi + prod_lo_carry, prod_lo', carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: prod_hi' = prod_hi + prod_lo_carry_limb, prod_lo', carry_limb, i, a_cur_loc, b_cur_loc, val, retdest DUP3 - // stack: carry, prod_hi', prod_lo', carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: carry_limb, prod_hi', prod_lo', carry_limb, i, a_cur_loc, b_cur_loc, val, retdest DUP3 - // stack: prod_lo', carry, prod_hi', prod_lo', carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: prod_lo', carry_limb, prod_hi', prod_lo', carry_limb, i, a_cur_loc, b_cur_loc, val, retdest ADD %shl_const(128) %shr_const(128) - // stack: to_write = (prod_lo' + carry) % 2^128, prod_hi', prod_lo', carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: to_write = (prod_lo' + carry_limb) % 2^128, prod_hi', prod_lo', carry_limb, i, a_cur_loc, b_cur_loc, val, retdest SWAP2 - // stack: prod_lo', prod_hi', to_write, carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: prod_lo', prod_hi', to_write, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest DUP3 - // stack: to_write, prod_lo', prod_hi', to_write, carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: to_write, prod_lo', prod_hi', to_write, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest LT - // stack: carry_new = to_write < prod_lo', prod_hi', to_write, carry, i, a_cur_loc, b_cur_loc, val, retdest + // 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_new, prod_hi', to_write, i, a_cur_loc, b_cur_loc, val, retdest + // stack: carry_limb_new, prod_hi', to_write, i, a_cur_loc, b_cur_loc, val, retdest ADD - // stack: carry = carry_new' + prod_hi', to_write, i, a_cur_loc, b_cur_loc, val, retdest + // stack: carry_limb = carry_limb_new' + prod_hi', to_write, i, a_cur_loc, b_cur_loc, val, retdest SWAP1 - // stack: to_write, carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: to_write, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest DUP4 - // stack: a_cur_loc, to_write, carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: a_cur_loc, to_write, carry_limb, i, a_cur_loc, b_cur_loc, val, retdest %mstore_kernel_general - // stack: carry, i, a_cur_loc, b_cur_loc, val, retdest + // stack: carry_limb, i, a_cur_loc, b_cur_loc, val, retdest SWAP1 - // stack: i, carry, a_cur_loc, b_cur_loc, val, retdest + // stack: i, carry_limb, a_cur_loc, b_cur_loc, val, retdest %decrement - // stack: i-1, carry, a_cur_loc, b_cur_loc, val, retdest + // stack: i-1, carry_limb, a_cur_loc, b_cur_loc, val, retdest SWAP2 - // stack: a_cur_loc, carry, i-1, b_cur_loc, val, retdest + // stack: a_cur_loc, carry_limb, i-1, b_cur_loc, val, retdest %increment - // stack: a_cur_loc+1, carry, i-1, b_cur_loc, val, retdest + // stack: a_cur_loc+1, carry_limb, i-1, b_cur_loc, val, retdest SWAP3 - // stack: b_cur_loc, carry, i-1, a_cur_loc+1, val, retdest + // stack: b_cur_loc, carry_limb, i-1, a_cur_loc+1, val, retdest %increment - // stack: b_cur_loc+1, carry, i-1, a_cur_loc+1, val, retdest + // 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, i-1, a_cur_loc+1, b_cur_loc+1, val, retdest + // stack: carry_limb, i-1, a_cur_loc+1, b_cur_loc+1, val, retdest DUP2 - // stack: i-1, carry, i-1, a_cur_loc+1, b_cur_loc+1, val, retdest + // stack: i-1, carry_limb, i-1, a_cur_loc+1, b_cur_loc+1, val, retdest %jumpi(addmul_loop) addmul_end: - // stack: carry_new, i-1, a_cur_loc+1, b_cur_loc+1, val, retdest + // 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_new, retdest + // stack: carry_limb_new, retdest SWAP1 - // stack: retdest, carry_new + // stack: retdest, carry_limb_new JUMP len_zero: // stack: len, a_start_loc, b_start_loc, val, retdest %pop4 // stack: retdest PUSH 0 - // stack: carry=0, retdest + // stack: carry_limb=0, retdest SWAP1 JUMP diff --git a/evm/src/cpu/kernel/asm/bignum/mul.asm b/evm/src/cpu/kernel/asm/bignum/mul.asm index cbf6a645..a7d19fb5 100644 --- a/evm/src/cpu/kernel/asm/bignum/mul.asm +++ b/evm/src/cpu/kernel/asm/bignum/mul.asm @@ -14,27 +14,27 @@ global mul_bignum: // stack: n=len, 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 - PUSH mul_return - // stack: mul_return, n, 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_return, n, len, a_start_loc, bi, output_cur, retdest + // stack: bi, mul_addmul_return, n, len, a_start_loc, bi, output_cur, retdest %mload_kernel_general - // stack: b[i], mul_return, n, len, a_start_loc, bi, output_cur, retdest, b + // stack: b[i], mul_addmul_return, n, len, a_start_loc, bi, output_cur, retdest, b DUP5 - // stack: a_start_loc, b[i], mul_return, n, len, a_start_loc, bi, output_cur, retdest, b + // 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_return, n, len, a_start_loc, bi, output_cur, retdest, b + // stack: output_loc, a_start_loc, b[i], mul_addmul_return, n, len, a_start_loc, bi, output_cur, retdest, b DUP6 - // stack: len, output_loc, a_start_loc, b[i], mul_return, n, len, a_start_loc, bi, output_cur, retdest, b + // stack: len, output_loc, a_start_loc, b[i], mul_addmul_return, n, len, a_start_loc, bi, output_cur, retdest, b %jump(addmul_bignum) -mul_return: - // stack: carry, n, len, a_start_loc, bi, output_cur, retdest +mul_addmul_return: + // stack: carry_limb, n, len, a_start_loc, bi, output_cur, retdest DUP6 - // stack: output_cur, carry, n, len, a_start_loc, bi, output_cur, retdest + // stack: output_cur, carry_limb, n, len, a_start_loc, bi, output_cur, retdest DUP4 - // stack: len, output_cur, carry, n, len, a_start_loc, bi, output_cur, retdest + // stack: len, output_cur, carry_limb, n, len, a_start_loc, bi, output_cur, retdest ADD - // stack: output_cur + len, carry, n, len, a_start_loc, bi, output_cur, retdest + // stack: output_cur + len, carry_limb, n, len, a_start_loc, bi, output_cur, retdest %mstore_kernel_general // stack: n, len, a_start_loc, bi, output_cur, retdest %decrement diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index 9dbcf6b7..0dd02bfa 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -291,9 +291,9 @@ where interpreter.run()?; // Determine actual result. - let carry = interpreter.stack()[0]; + let carry_limb = interpreter.stack()[0]; let mut new_memory = interpreter.get_kernel_general_memory(); - new_memory[len] = carry; + new_memory[len] = carry_limb; let actual_result: Vec<_> = new_memory[..expected_result.len()].into(); // Compare. From ad38f957415b93a0bf6093b7b3d7fb98c7644387 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 15 Mar 2023 13:45:55 -0700 Subject: [PATCH 33/62] TODO for possible future mul optimization --- evm/src/cpu/kernel/asm/bignum/mul.asm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/evm/src/cpu/kernel/asm/bignum/mul.asm b/evm/src/cpu/kernel/asm/bignum/mul.asm index a7d19fb5..8317fdbc 100644 --- a/evm/src/cpu/kernel/asm/bignum/mul.asm +++ b/evm/src/cpu/kernel/asm/bignum/mul.asm @@ -4,6 +4,8 @@ // Stores a * b in output_loc, leaving a and b unchanged. // Both a and b have length len; a * b will have length 2 * len. // output_loc must be initialized as 2 * len zeroes. +// TODO: possible optimization: allow output_loc to be uninitialized, and write over it with a[0:len] * b[0] (a multiplication +// with carry) in place of the first addmul. global mul_bignum: // stack: len, a_start_loc, b_start_loc, output_loc, retdest DUP1 From 4ef981e415bb63171a0eb38ce92b5181dc5dae62 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 15 Mar 2023 14:19:54 -0700 Subject: [PATCH 34/62] initial test data --- evm/src/cpu/kernel/tests/bignum.rs | 35 +++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index 0dd02bfa..cc6b972e 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -1,3 +1,5 @@ +use std::f32::MIN; + use anyhow::Result; use ethereum_types::U256; use itertools::Itertools; @@ -8,9 +10,37 @@ use rand::Rng; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; -use crate::util::{biguint_to_mem_vec, mem_vec_to_biguint}; +use crate::util::{biguint_to_mem_vec, mem_vec_to_biguint, u256_to_biguint}; const BIGNUM_LIMB_BITS: usize = 128; +const MINUS_ONE: U256 = U256::MAX; + +fn test_data() -> Vec> { + let unary_op_inputs = vec![0u8.into(), 1u8.into(), 2u8.into()]; + + let shr_outputs = vec![0u8.into(), 0u8.into(), 1u8.into()]; + let iszero_outputs = vec![1u8.into(), 0u8.into(), 0u8.into()]; + + let binary_op_first_inputs = vec![0u8.into(), 1u8.into(), 2u8.into()]; + let binary_op_second_inputs = vec![0u8.into(), 2u8.into(), 1u8.into()]; + + let cmp_outputs = vec![0u8.into(), u256_to_biguint(MINUS_ONE), 1u8.into()]; + let add_outputs = vec![0u8.into(), 3u8.into(), 3u8.into()]; + let addmul_outputs = vec![0u8.into(), 2u8.into(), 4u8.into()]; + let mul_outputs = vec![0u8.into(), 2u8.into(), 2u8.into()]; + + vec![ + unary_op_inputs, + shr_outputs, + iszero_outputs, + binary_op_first_inputs, + binary_op_second_inputs, + cmp_outputs, + add_outputs, + addmul_outputs, + mul_outputs, + ] +} fn pad_bignums(biguints: &[BigUint], length: usize) -> Vec { biguints @@ -207,8 +237,7 @@ where interpreter.set_kernel_general_memory(memory.clone()); interpreter.run()?; let result = interpreter.stack()[0]; - let minus_one = ((U256::one() << 255) - 1) * 2 + 1; - assert_eq!(result, minus_one); + assert_eq!(result, MINUS_ONE); // Test equal case. let mut initial_stack: Vec = vec![length, a_start_loc, a_start_loc, retdest]; From b0ed6ae0d3508ec9ad557b466fae3982bacaf638 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 15 Mar 2023 14:32:18 -0700 Subject: [PATCH 35/62] cleanup --- evm/src/cpu/kernel/tests/bignum.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index cc6b972e..566ace84 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -1,5 +1,3 @@ -use std::f32::MIN; - use anyhow::Result; use ethereum_types::U256; use itertools::Itertools; @@ -15,6 +13,7 @@ use crate::util::{biguint_to_mem_vec, mem_vec_to_biguint, u256_to_biguint}; const BIGNUM_LIMB_BITS: usize = 128; const MINUS_ONE: U256 = U256::MAX; +#[allow(dead_code)] fn test_data() -> Vec> { let unary_op_inputs = vec![0u8.into(), 1u8.into(), 2u8.into()]; From 6f8a510042067299acad0959aacdf8bcaf83bb59 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 15 Mar 2023 14:57:46 -0700 Subject: [PATCH 36/62] interface changes --- evm/src/cpu/kernel/tests/bignum.rs | 87 ++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 27 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index 566ace84..3e53995b 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -8,37 +8,15 @@ use rand::Rng; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; -use crate::util::{biguint_to_mem_vec, mem_vec_to_biguint, u256_to_biguint}; +use crate::util::{biguint_to_mem_vec, mem_vec_to_biguint}; const BIGNUM_LIMB_BITS: usize = 128; const MINUS_ONE: U256 = U256::MAX; -#[allow(dead_code)] -fn test_data() -> Vec> { - let unary_op_inputs = vec![0u8.into(), 1u8.into(), 2u8.into()]; - - let shr_outputs = vec![0u8.into(), 0u8.into(), 1u8.into()]; - let iszero_outputs = vec![1u8.into(), 0u8.into(), 0u8.into()]; - - let binary_op_first_inputs = vec![0u8.into(), 1u8.into(), 2u8.into()]; - let binary_op_second_inputs = vec![0u8.into(), 2u8.into(), 1u8.into()]; - - let cmp_outputs = vec![0u8.into(), u256_to_biguint(MINUS_ONE), 1u8.into()]; - let add_outputs = vec![0u8.into(), 3u8.into(), 3u8.into()]; - let addmul_outputs = vec![0u8.into(), 2u8.into(), 4u8.into()]; - let mul_outputs = vec![0u8.into(), 2u8.into(), 2u8.into()]; - - vec![ - unary_op_inputs, - shr_outputs, - iszero_outputs, - binary_op_first_inputs, - binary_op_second_inputs, - cmp_outputs, - add_outputs, - addmul_outputs, - mul_outputs, - ] +fn test_data() -> Vec { + let mut data = vec![0u8.into(), 1u8.into(), u128::MAX.into()]; + data.sort(); + data } fn pad_bignums(biguints: &[BigUint], length: usize) -> Vec { @@ -98,6 +76,14 @@ fn prepare_bignum_min(_bit_size: usize) -> (BigUint, U256, Vec) { (a, length, a_limbs) } +fn prepare_bignum_from_test_data(i: usize) -> (BigUint, U256, Vec) { + let a = test_data()[i].clone(); + let length: U256 = bignum_len(&a).into(); + let a_limbs = biguint_to_mem_vec(a.clone()); + + (a, length, a_limbs) +} + fn prepare_two_bignums_random(bit_size: usize) -> (BigUint, BigUint, U256, Vec) { let (a, b) = gen_two_bignums_ordered(bit_size); let length: U256 = bignum_len(&a).into(); @@ -142,6 +128,15 @@ fn prepare_two_bignums_zero(_bit_size: usize) -> (BigUint, BigUint, U256, Vec (BigUint, BigUint, U256, Vec) { + let a = test_data()[i].clone(); + let b = test_data()[j].clone(); + let length: U256 = bignum_len(&a).into(); + let memory = pad_bignums(&[a.clone(), b.clone()], length.try_into().unwrap()); + + (a, b, length, memory) +} + fn test_shr_bignum(prepare_bignum_fn: &F) -> Result<()> where F: Fn(usize) -> (BigUint, U256, Vec), @@ -375,6 +370,11 @@ fn test_shr_bignum_all() -> Result<()> { test_shr_bignum(&prepare_bignum_max)?; test_shr_bignum(&prepare_bignum_min)?; + let test_data = test_data(); + for i in 0..test_data.len() { + test_shr_bignum(&|_| prepare_bignum_from_test_data(i))?; + } + Ok(()) } @@ -384,6 +384,11 @@ fn test_iszero_bignum_all() -> Result<()> { test_iszero_bignum(&prepare_bignum_max)?; // No need to test for min, since it is zero. + let test_data = test_data(); + for i in 0..test_data.len() { + test_iszero_bignum(&|_| prepare_bignum_from_test_data(i))?; + } + Ok(()) } @@ -394,6 +399,13 @@ fn test_cmp_bignum_all() -> Result<()> { test_cmp_bignum(&prepare_two_bignums_min)?; test_cmp_bignum(&prepare_two_bignums_diff)?; + let test_data = test_data(); + for i in 0..test_data.len() { + for j in 0..i { + test_cmp_bignum(&|_| prepare_two_bignums_from_test_data(i, j))?; + } + } + Ok(()) } @@ -405,6 +417,13 @@ fn test_add_bignum_all() -> Result<()> { test_add_bignum(&prepare_two_bignums_diff)?; test_add_bignum(&prepare_two_bignums_zero)?; + let test_data = test_data(); + for i in 0..test_data.len() { + for j in 0..i { + test_add_bignum(&|_| prepare_two_bignums_from_test_data(i, j))?; + } + } + Ok(()) } @@ -416,6 +435,13 @@ fn test_addmul_bignum_all() -> Result<()> { test_addmul_bignum(&prepare_two_bignums_diff)?; test_addmul_bignum(&prepare_two_bignums_zero)?; + let test_data = test_data(); + for i in 0..test_data.len() { + for j in 0..i { + test_addmul_bignum(&|_| prepare_two_bignums_from_test_data(i, j))?; + } + } + Ok(()) } @@ -427,5 +453,12 @@ fn test_mul_bignum_all() -> Result<()> { test_mul_bignum(&prepare_two_bignums_diff)?; test_mul_bignum(&prepare_two_bignums_zero)?; + let test_data = test_data(); + for i in 0..test_data.len() { + for j in 0..i { + test_mul_bignum(&|_| prepare_two_bignums_from_test_data(i, j))?; + } + } + Ok(()) } From 44a0596f8dee79d2f74f92d4c55f888740c2a59a Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 15 Mar 2023 18:38:31 -0700 Subject: [PATCH 37/62] fmt --- evm/src/cpu/kernel/asm/bignum/add.asm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/asm/bignum/add.asm b/evm/src/cpu/kernel/asm/bignum/add.asm index 64293f11..7f646097 100644 --- a/evm/src/cpu/kernel/asm/bignum/add.asm +++ b/evm/src/cpu/kernel/asm/bignum/add.asm @@ -67,4 +67,4 @@ len_zero: PUSH 0 // stack: carry=0, retdest SWAP1 - JUMP \ No newline at end of file + JUMP From e97e8188334d4a8a6a9f4a1e46ea59e8636af986 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 15 Mar 2023 19:25:51 -0700 Subject: [PATCH 38/62] fixed iszero and cleanup --- evm/src/cpu/kernel/tests/bignum.rs | 33 ++++++++++++++++++------------ 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index 3e53995b..bce91295 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -76,12 +76,11 @@ fn prepare_bignum_min(_bit_size: usize) -> (BigUint, U256, Vec) { (a, length, a_limbs) } -fn prepare_bignum_from_test_data(i: usize) -> (BigUint, U256, Vec) { - let a = test_data()[i].clone(); +fn prepare_bignum_from_value(a: BigUint) -> (BigUint, U256, Vec) { let length: U256 = bignum_len(&a).into(); let a_limbs = biguint_to_mem_vec(a.clone()); - (a, length, a_limbs) + (a.clone(), length, a_limbs) } fn prepare_two_bignums_random(bit_size: usize) -> (BigUint, BigUint, U256, Vec) { @@ -128,13 +127,11 @@ fn prepare_two_bignums_zero(_bit_size: usize) -> (BigUint, BigUint, U256, Vec (BigUint, BigUint, U256, Vec) { - let a = test_data()[i].clone(); - let b = test_data()[j].clone(); +fn prepare_two_bignums_from_values(a: BigUint, b: BigUint) -> (BigUint, BigUint, U256, Vec) { let length: U256 = bignum_len(&a).into(); let memory = pad_bignums(&[a.clone(), b.clone()], length.try_into().unwrap()); - (a, b, length, memory) + (a.clone(), b.clone(), length, memory) } fn test_shr_bignum(prepare_bignum_fn: &F) -> Result<()> @@ -372,7 +369,7 @@ fn test_shr_bignum_all() -> Result<()> { let test_data = test_data(); for i in 0..test_data.len() { - test_shr_bignum(&|_| prepare_bignum_from_test_data(i))?; + test_shr_bignum(&|_| prepare_bignum_from_value(test_data[i].clone()))?; } Ok(()) @@ -386,7 +383,9 @@ fn test_iszero_bignum_all() -> Result<()> { let test_data = test_data(); for i in 0..test_data.len() { - test_iszero_bignum(&|_| prepare_bignum_from_test_data(i))?; + if test_data[i] != 0u8.into() { + test_iszero_bignum(&|_| prepare_bignum_from_value(test_data[i].clone()))?; + } } Ok(()) @@ -402,7 +401,9 @@ fn test_cmp_bignum_all() -> Result<()> { let test_data = test_data(); for i in 0..test_data.len() { for j in 0..i { - test_cmp_bignum(&|_| prepare_two_bignums_from_test_data(i, j))?; + test_cmp_bignum(&|_| { + prepare_two_bignums_from_values(test_data[i].clone(), test_data[j].clone()) + })?; } } @@ -420,7 +421,9 @@ fn test_add_bignum_all() -> Result<()> { let test_data = test_data(); for i in 0..test_data.len() { for j in 0..i { - test_add_bignum(&|_| prepare_two_bignums_from_test_data(i, j))?; + test_add_bignum(&|_| { + prepare_two_bignums_from_values(test_data[i].clone(), test_data[j].clone()) + })?; } } @@ -438,7 +441,9 @@ fn test_addmul_bignum_all() -> Result<()> { let test_data = test_data(); for i in 0..test_data.len() { for j in 0..i { - test_addmul_bignum(&|_| prepare_two_bignums_from_test_data(i, j))?; + test_addmul_bignum(&|_| { + prepare_two_bignums_from_values(test_data[i].clone(), test_data[j].clone()) + })?; } } @@ -456,7 +461,9 @@ fn test_mul_bignum_all() -> Result<()> { let test_data = test_data(); for i in 0..test_data.len() { for j in 0..i { - test_mul_bignum(&|_| prepare_two_bignums_from_test_data(i, j))?; + test_mul_bignum(&|_| { + prepare_two_bignums_from_values(test_data[i].clone(), test_data[j].clone()) + })?; } } From 54eb29e7070a86c601b33e9f82090c8f883206e9 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 15 Mar 2023 19:58:26 -0700 Subject: [PATCH 39/62] fix --- evm/src/util.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm/src/util.rs b/evm/src/util.rs index 6b2ca479..fba97372 100644 --- a/evm/src/util.rs +++ b/evm/src/util.rs @@ -170,8 +170,8 @@ pub(crate) fn mem_vec_to_biguint(x: &[U256]) -> BigUint { pub(crate) fn biguint_to_le_limbs(x: BigUint) -> Vec { let mut digits = x.to_u32_digits(); - // Pad to a multiple of 8. - digits.resize((digits.len() + 7) / 8 * 8, 0); + // Pad to a multiple of 4. + digits.resize((digits.len() + 3) / 4 * 4, 0); digits .chunks(4) From e60271424ce8fbc787e35c17464b92de3d566b41 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 15 Mar 2023 19:59:04 -0700 Subject: [PATCH 40/62] cleanup --- evm/src/cpu/kernel/tests/bignum.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index bce91295..25b11c17 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -80,7 +80,7 @@ fn prepare_bignum_from_value(a: BigUint) -> (BigUint, U256, Vec) { let length: U256 = bignum_len(&a).into(); let a_limbs = biguint_to_mem_vec(a.clone()); - (a.clone(), length, a_limbs) + (a, length, a_limbs) } fn prepare_two_bignums_random(bit_size: usize) -> (BigUint, BigUint, U256, Vec) { @@ -131,7 +131,7 @@ fn prepare_two_bignums_from_values(a: BigUint, b: BigUint) -> (BigUint, BigUint, let length: U256 = bignum_len(&a).into(); let memory = pad_bignums(&[a.clone(), b.clone()], length.try_into().unwrap()); - (a.clone(), b.clone(), length, memory) + (a, b, length, memory) } fn test_shr_bignum(prepare_bignum_fn: &F) -> Result<()> From 73633354e00f9697d4ae356f6ed3bf514eebc3e7 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 15 Mar 2023 22:30:17 -0700 Subject: [PATCH 41/62] test data --- evm/src/cpu/kernel/tests/bignum.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index 25b11c17..17a68d89 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -1,3 +1,5 @@ +use std::str::FromStr; + use anyhow::Result; use ethereum_types::U256; use itertools::Itertools; @@ -14,7 +16,21 @@ const BIGNUM_LIMB_BITS: usize = 128; const MINUS_ONE: U256 = U256::MAX; fn test_data() -> Vec { - let mut data = vec![0u8.into(), 1u8.into(), u128::MAX.into()]; + let mut data = vec![0u128.into(), 1u128.into(), u128::MAX.into(), + 21u128.into(), +908u128.into(), +1267650597867046177654064545792u128.into(), +BigUint::from_str("57896044618658097611351864738157061705262361561497619362091104892532012613632").unwrap(), +BigUint::from_str("115792089237105570840234253759177109864155645142784332660520492325483608801280").unwrap(), +BigUint::from_str("231583736816786089484927226016147767929578972263620494977377884571370600267775").unwrap(), +BigUint::from_str("3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792").unwrap(), +BigUint::from_str("5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287").unwrap(), +BigUint::from_str("13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159").unwrap(), +BigUint::from_str("26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232").unwrap(), +BigUint::from_str("10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216").unwrap(), +BigUint::from_str("35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271").unwrap(), + ]; + data.sort(); data } From 534395ee4d8587938e40ebf1c688b7e7e656b185 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 15 Mar 2023 22:30:54 -0700 Subject: [PATCH 42/62] fmt --- evm/src/cpu/kernel/tests/bignum.rs | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index 17a68d89..1d4196b2 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -16,19 +16,22 @@ const BIGNUM_LIMB_BITS: usize = 128; const MINUS_ONE: U256 = U256::MAX; fn test_data() -> Vec { - let mut data = vec![0u128.into(), 1u128.into(), u128::MAX.into(), - 21u128.into(), -908u128.into(), -1267650597867046177654064545792u128.into(), -BigUint::from_str("57896044618658097611351864738157061705262361561497619362091104892532012613632").unwrap(), -BigUint::from_str("115792089237105570840234253759177109864155645142784332660520492325483608801280").unwrap(), -BigUint::from_str("231583736816786089484927226016147767929578972263620494977377884571370600267775").unwrap(), -BigUint::from_str("3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792").unwrap(), -BigUint::from_str("5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287").unwrap(), -BigUint::from_str("13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159").unwrap(), -BigUint::from_str("26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232").unwrap(), -BigUint::from_str("10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216").unwrap(), -BigUint::from_str("35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271").unwrap(), + let mut data = vec![ + 0u128.into(), + 1u128.into(), + u128::MAX.into(), + 21u128.into(), + 908u128.into(), + 1267650597867046177654064545792u128.into(), + BigUint::from_str("57896044618658097611351864738157061705262361561497619362091104892532012613632").unwrap(), + BigUint::from_str("115792089237105570840234253759177109864155645142784332660520492325483608801280").unwrap(), + BigUint::from_str("231583736816786089484927226016147767929578972263620494977377884571370600267775").unwrap(), + BigUint::from_str("3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792").unwrap(), + BigUint::from_str("5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287").unwrap(), + BigUint::from_str("13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159").unwrap(), + BigUint::from_str("26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232").unwrap(), + BigUint::from_str("10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216").unwrap(), + BigUint::from_str("35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271").unwrap(), ]; data.sort(); From 4e736b63b8c712940b24842e934ca6aa73d77952 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 15 Mar 2023 23:05:44 -0700 Subject: [PATCH 43/62] fixes --- evm/src/cpu/kernel/asm/bignum/add.asm | 19 ++++++++----------- evm/src/cpu/kernel/tests/bignum.rs | 7 ++++++- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/evm/src/cpu/kernel/asm/bignum/add.asm b/evm/src/cpu/kernel/asm/bignum/add.asm index 7f646097..09b405e8 100644 --- a/evm/src/cpu/kernel/asm/bignum/add.asm +++ b/evm/src/cpu/kernel/asm/bignum/add.asm @@ -29,25 +29,22 @@ add_loop: // 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 - %shl_const(128) - %shr_const(128) + %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_kernel_general // stack: carry_new, i, a_cur_loc, b_cur_loc, retdest - %stack (c, i, a, b) -> (a, b, c, i) - // stack: a_cur_loc, b_cur_loc, carry_new, i, retdest + SWAP2 %increment - // stack: a_cur_loc + 1, b_cur_loc, carry_new, i, retdest + 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 - // stack: b_cur_loc, a_cur_loc + 1, carry_new, i, retdest - %increment - // stack: b_cur_loc + 1, a_cur_loc + 1, carry_new, i, retdest - %stack (b, a, c, i) -> (i, c, a, b) - // stack: i, carry_new, a_cur_loc + 1, b_cur_loc + 1, retdest %decrement - // stack: i - 1, carry_new, a_cur_loc + 1, b_cur_loc + 1, retdest SWAP1 // stack: carry_new, i - 1, a_cur_loc + 1, b_cur_loc + 1, retdest DUP2 diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index 1d4196b2..bd3daa95 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -20,6 +20,8 @@ fn test_data() -> Vec { 0u128.into(), 1u128.into(), u128::MAX.into(), + + // Generated by GMP's mpz_rrandomb for bit lengths 5, 10, 100, 255, 256, 257, 500, 511, 512, 513, 1000, and 1500. 21u128.into(), 908u128.into(), 1267650597867046177654064545792u128.into(), @@ -266,6 +268,7 @@ where F: Fn(usize) -> (BigUint, BigUint, U256, Vec), { let (a, b, length, memory) = prepare_two_bignums_fn(1000); + let len: usize = length.try_into().unwrap(); // Determine expected sum. let sum = a + b; @@ -288,7 +291,9 @@ where interpreter.run()?; // Determine actual sum. - let new_memory = interpreter.get_kernel_general_memory(); + let carry_limb = interpreter.stack()[0]; + let mut new_memory = interpreter.get_kernel_general_memory(); + new_memory[len] = carry_limb; let actual_sum: Vec<_> = new_memory[..expected_sum.len()].into(); // Compare. From ee9bfb0822633af0dc0599609fbdebc0c0f59ab1 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 15 Mar 2023 23:11:39 -0700 Subject: [PATCH 44/62] fix --- evm/src/cpu/kernel/tests/bignum.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs index bd3daa95..2d59988f 100644 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ b/evm/src/cpu/kernel/tests/bignum.rs @@ -290,10 +290,12 @@ where // Run add function. interpreter.run()?; - // Determine actual sum. + // Determine actual sum, appending the final carry if nonzero. let carry_limb = interpreter.stack()[0]; let mut new_memory = interpreter.get_kernel_general_memory(); - new_memory[len] = carry_limb; + if carry_limb > 0.into() { + new_memory[len] = carry_limb; + } let actual_sum: Vec<_> = new_memory[..expected_sum.len()].into(); // Compare. From fa3443a50bda812b5c6bbd7429098549f7a31765 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 16 Mar 2023 10:52:20 -0700 Subject: [PATCH 45/62] new testing interface, and test data --- evm/src/cpu/kernel/tests/bignum.rs | 497 ------ evm/src/cpu/kernel/tests/bignum/mod.rs | 356 +++++ .../kernel/tests/bignum/test_data/add_outputs | 225 +++ .../tests/bignum/test_data/addmul_outputs | 1350 +++++++++++++++++ .../tests/bignum/test_data/bignum_inputs | 15 + .../kernel/tests/bignum/test_data/cmp_outputs | 225 +++ .../tests/bignum/test_data/iszero_outputs | 15 + .../kernel/tests/bignum/test_data/mul_outputs | 225 +++ .../kernel/tests/bignum/test_data/shr_outputs | 15 + .../kernel/tests/bignum/test_data/u128_inputs | 6 + 10 files changed, 2432 insertions(+), 497 deletions(-) delete mode 100644 evm/src/cpu/kernel/tests/bignum.rs create mode 100644 evm/src/cpu/kernel/tests/bignum/mod.rs create mode 100644 evm/src/cpu/kernel/tests/bignum/test_data/add_outputs create mode 100644 evm/src/cpu/kernel/tests/bignum/test_data/addmul_outputs create mode 100644 evm/src/cpu/kernel/tests/bignum/test_data/bignum_inputs create mode 100644 evm/src/cpu/kernel/tests/bignum/test_data/cmp_outputs create mode 100644 evm/src/cpu/kernel/tests/bignum/test_data/iszero_outputs create mode 100644 evm/src/cpu/kernel/tests/bignum/test_data/mul_outputs create mode 100644 evm/src/cpu/kernel/tests/bignum/test_data/shr_outputs create mode 100644 evm/src/cpu/kernel/tests/bignum/test_data/u128_inputs diff --git a/evm/src/cpu/kernel/tests/bignum.rs b/evm/src/cpu/kernel/tests/bignum.rs deleted file mode 100644 index 2d59988f..00000000 --- a/evm/src/cpu/kernel/tests/bignum.rs +++ /dev/null @@ -1,497 +0,0 @@ -use std::str::FromStr; - -use anyhow::Result; -use ethereum_types::U256; -use itertools::Itertools; -use num::{BigUint, One, Zero}; -use num_bigint::RandBigInt; -use plonky2_util::ceil_div_usize; -use rand::Rng; - -use crate::cpu::kernel::aggregator::KERNEL; -use crate::cpu::kernel::interpreter::Interpreter; -use crate::util::{biguint_to_mem_vec, mem_vec_to_biguint}; - -const BIGNUM_LIMB_BITS: usize = 128; -const MINUS_ONE: U256 = U256::MAX; - -fn test_data() -> Vec { - let mut data = vec![ - 0u128.into(), - 1u128.into(), - u128::MAX.into(), - - // Generated by GMP's mpz_rrandomb for bit lengths 5, 10, 100, 255, 256, 257, 500, 511, 512, 513, 1000, and 1500. - 21u128.into(), - 908u128.into(), - 1267650597867046177654064545792u128.into(), - BigUint::from_str("57896044618658097611351864738157061705262361561497619362091104892532012613632").unwrap(), - BigUint::from_str("115792089237105570840234253759177109864155645142784332660520492325483608801280").unwrap(), - BigUint::from_str("231583736816786089484927226016147767929578972263620494977377884571370600267775").unwrap(), - BigUint::from_str("3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792").unwrap(), - BigUint::from_str("5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287").unwrap(), - BigUint::from_str("13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159").unwrap(), - BigUint::from_str("26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232").unwrap(), - BigUint::from_str("10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216").unwrap(), - BigUint::from_str("35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271").unwrap(), - ]; - - data.sort(); - data -} - -fn pad_bignums(biguints: &[BigUint], length: usize) -> Vec { - biguints - .iter() - .flat_map(|biguint| { - biguint_to_mem_vec(biguint.clone()) - .into_iter() - .pad_using(length, |_| U256::zero()) - }) - .collect() -} - -fn gen_bignum(bit_size: usize) -> BigUint { - let mut rng = rand::thread_rng(); - rng.gen_biguint(bit_size as u64) -} - -fn bignum_len(a: &BigUint) -> usize { - ceil_div_usize(a.bits() as usize, BIGNUM_LIMB_BITS) -} - -fn gen_two_bignums_ordered(bit_size: usize) -> (BigUint, BigUint) { - let mut rng = rand::thread_rng(); - let (a, b) = ( - rng.gen_biguint(bit_size as u64), - rng.gen_biguint(bit_size as u64), - ); - if b < a { - (a, b) - } else { - (b, a) - } -} - -fn prepare_bignum_random(bit_size: usize) -> (BigUint, U256, Vec) { - let a = gen_bignum(bit_size); - let length: U256 = bignum_len(&a).into(); - let a_limbs = biguint_to_mem_vec(a.clone()); - - (a, length, a_limbs) -} - -fn prepare_bignum_max(bit_size: usize) -> (BigUint, U256, Vec) { - let a = (BigUint::one() << bit_size) - BigUint::one(); - let length: U256 = bignum_len(&a).into(); - let a_limbs = biguint_to_mem_vec(a.clone()); - - (a, length, a_limbs) -} - -fn prepare_bignum_min(_bit_size: usize) -> (BigUint, U256, Vec) { - let a = BigUint::zero(); - let length: U256 = bignum_len(&a).into(); - let a_limbs = biguint_to_mem_vec(a.clone()); - - (a, length, a_limbs) -} - -fn prepare_bignum_from_value(a: BigUint) -> (BigUint, U256, Vec) { - let length: U256 = bignum_len(&a).into(); - let a_limbs = biguint_to_mem_vec(a.clone()); - - (a, length, a_limbs) -} - -fn prepare_two_bignums_random(bit_size: usize) -> (BigUint, BigUint, U256, Vec) { - let (a, b) = gen_two_bignums_ordered(bit_size); - let length: U256 = bignum_len(&a).into(); - let memory = pad_bignums(&[a.clone(), b.clone()], length.try_into().unwrap()); - - (a, b, length, memory) -} - -fn prepare_two_bignums_max(bit_size: usize) -> (BigUint, BigUint, U256, Vec) { - let a = (BigUint::one() << bit_size) - BigUint::one(); - let b = (BigUint::one() << bit_size) - BigUint::from(2u8); - let length: U256 = bignum_len(&a).into(); - let memory = pad_bignums(&[a.clone(), b.clone()], length.try_into().unwrap()); - - (a, b, length, memory) -} - -fn prepare_two_bignums_min(_bit_size: usize) -> (BigUint, BigUint, U256, Vec) { - let a = BigUint::one(); - let b = BigUint::zero(); - let length: U256 = bignum_len(&a).into(); - let memory = pad_bignums(&[a.clone(), b.clone()], length.try_into().unwrap()); - - (a, b, length, memory) -} - -fn prepare_two_bignums_diff(bit_size: usize) -> (BigUint, BigUint, U256, Vec) { - let a = BigUint::one() << (bit_size - 1); - let b = BigUint::zero(); - let length: U256 = bignum_len(&a).into(); - let memory = pad_bignums(&[a.clone(), b.clone()], length.try_into().unwrap()); - - (a, b, length, memory) -} - -fn prepare_two_bignums_zero(_bit_size: usize) -> (BigUint, BigUint, U256, Vec) { - let a = BigUint::zero(); - let b = BigUint::zero(); - let length: U256 = bignum_len(&a).into(); - let memory = pad_bignums(&[a.clone(), b.clone()], length.try_into().unwrap()); - - (a, b, length, memory) -} - -fn prepare_two_bignums_from_values(a: BigUint, b: BigUint) -> (BigUint, BigUint, U256, Vec) { - let length: U256 = bignum_len(&a).into(); - let memory = pad_bignums(&[a.clone(), b.clone()], length.try_into().unwrap()); - - (a, b, length, memory) -} - -fn test_shr_bignum(prepare_bignum_fn: &F) -> Result<()> -where - F: Fn(usize) -> (BigUint, U256, Vec), -{ - let (a, length, memory) = prepare_bignum_fn(1000); - - let halved = a >> 1; - - let retdest = 0xDEADBEEFu32.into(); - let shr_bignum = KERNEL.global_labels["shr_bignum"]; - - let a_start_loc = 0.into(); - - let mut initial_stack: Vec = vec![length, a_start_loc, retdest]; - initial_stack.reverse(); - let mut interpreter = Interpreter::new_with_kernel(shr_bignum, initial_stack); - interpreter.set_kernel_general_memory(memory); - interpreter.run()?; - - let new_memory = interpreter.get_kernel_general_memory(); - let new_a = mem_vec_to_biguint(&new_memory[0..length.as_usize()]); - assert_eq!(new_a, halved); - - Ok(()) -} - -fn test_iszero_bignum(prepare_bignum_fn: &F) -> Result<()> -where - F: Fn(usize) -> (BigUint, U256, Vec), -{ - let (length, memory) = { - let (mut a, mut length, mut memory) = prepare_bignum_fn(1000); - while a == BigUint::zero() { - (a, length, memory) = prepare_bignum_fn(1000); - } - (length, memory) - }; - - let retdest = 0xDEADBEEFu32.into(); - let iszero_bignum = KERNEL.global_labels["iszero_bignum"]; - - let a_start_loc = 0.into(); - - // Test with a > 0. - let mut initial_stack: Vec = vec![length, a_start_loc, retdest]; - initial_stack.reverse(); - let mut interpreter = Interpreter::new_with_kernel(iszero_bignum, initial_stack); - interpreter.set_kernel_general_memory(memory.clone()); - interpreter.run()?; - let result = interpreter.stack()[0]; - assert_eq!(result, 0.into()); - - let memory = vec![0.into(); memory.len()]; - - // Test with a == 0. - let mut initial_stack: Vec = vec![length, a_start_loc, retdest]; - initial_stack.reverse(); - let mut interpreter = Interpreter::new_with_kernel(iszero_bignum, initial_stack); - interpreter.set_kernel_general_memory(memory); - interpreter.run()?; - let result = interpreter.stack()[0]; - assert_eq!(result, U256::one()); - - Ok(()) -} - -fn test_cmp_bignum(prepare_two_bignums_fn: &F) -> Result<()> -where - F: Fn(usize) -> (BigUint, BigUint, U256, Vec), -{ - let (_a, _b, length, memory) = prepare_two_bignums_fn(1000); - - let retdest = 0xDEADBEEFu32.into(); - let cmp_bignum = KERNEL.global_labels["cmp_bignum"]; - - let a_start_loc = 0.into(); - let b_start_loc = length; - - // Test with a > b. - let mut initial_stack: Vec = vec![length, a_start_loc, b_start_loc, retdest]; - initial_stack.reverse(); - let mut interpreter = Interpreter::new_with_kernel(cmp_bignum, initial_stack); - interpreter.set_kernel_general_memory(memory.clone()); - interpreter.run()?; - let result = interpreter.stack()[0]; - assert_eq!(result, U256::one()); - - // Swap a and b, to test the less-than case. - let mut initial_stack: Vec = vec![length, b_start_loc, a_start_loc, retdest]; - initial_stack.reverse(); - let mut interpreter = Interpreter::new_with_kernel(cmp_bignum, initial_stack); - interpreter.set_kernel_general_memory(memory.clone()); - interpreter.run()?; - let result = interpreter.stack()[0]; - assert_eq!(result, MINUS_ONE); - - // Test equal case. - let mut initial_stack: Vec = vec![length, a_start_loc, a_start_loc, retdest]; - initial_stack.reverse(); - let mut interpreter = Interpreter::new_with_kernel(cmp_bignum, initial_stack); - interpreter.set_kernel_general_memory(memory); - interpreter.run()?; - let result = interpreter.stack()[0]; - assert_eq!(result, U256::zero()); - - Ok(()) -} - -fn test_add_bignum(prepare_two_bignums_fn: &F) -> Result<()> -where - F: Fn(usize) -> (BigUint, BigUint, U256, Vec), -{ - let (a, b, length, memory) = prepare_two_bignums_fn(1000); - let len: usize = length.try_into().unwrap(); - - // Determine expected sum. - let sum = a + b; - let expected_sum: Vec = biguint_to_mem_vec(sum); - - let a_start_loc = 0.into(); - let b_start_loc = length; - - // Prepare stack. - let retdest = 0xDEADBEEFu32.into(); - let mut initial_stack: Vec = vec![length, a_start_loc, b_start_loc, retdest]; - initial_stack.reverse(); - - // Prepare interpreter. - let add_bignum = KERNEL.global_labels["add_bignum"]; - let mut interpreter = Interpreter::new_with_kernel(add_bignum, initial_stack); - interpreter.set_kernel_general_memory(memory); - - // Run add function. - interpreter.run()?; - - // Determine actual sum, appending the final carry if nonzero. - let carry_limb = interpreter.stack()[0]; - let mut new_memory = interpreter.get_kernel_general_memory(); - if carry_limb > 0.into() { - new_memory[len] = carry_limb; - } - let actual_sum: Vec<_> = new_memory[..expected_sum.len()].into(); - - // Compare. - assert_eq!(actual_sum, expected_sum); - - Ok(()) -} - -fn test_addmul_bignum(prepare_two_bignums_fn: &F) -> Result<()> -where - F: Fn(usize) -> (BigUint, BigUint, U256, Vec), -{ - let mut rng = rand::thread_rng(); - let (a, b, length, mut memory) = prepare_two_bignums_fn(1000); - let len: usize = length.try_into().unwrap(); - memory.splice(len..len, vec![0.into(); 2].iter().cloned()); - - let val: u128 = rng.gen(); - let val_u256 = U256::from(val); - - // Determine expected result. - let result = a + b * BigUint::from(val); - let expected_result: Vec = biguint_to_mem_vec(result); - - let a_start_loc = 0.into(); - let b_start_loc = length + 2; - - // Prepare stack. - let retdest = 0xDEADBEEFu32.into(); - let mut initial_stack: Vec = vec![length, a_start_loc, b_start_loc, val_u256, retdest]; - initial_stack.reverse(); - - // Prepare interpreter. - let addmul_bignum = KERNEL.global_labels["addmul_bignum"]; - let mut interpreter = Interpreter::new_with_kernel(addmul_bignum, initial_stack); - interpreter.set_kernel_general_memory(memory); - - // Run add function. - interpreter.run()?; - - // Determine actual result. - let carry_limb = interpreter.stack()[0]; - let mut new_memory = interpreter.get_kernel_general_memory(); - new_memory[len] = carry_limb; - let actual_result: Vec<_> = new_memory[..expected_result.len()].into(); - - // Compare. - assert_eq!(actual_result, expected_result); - - Ok(()) -} - -fn test_mul_bignum(prepare_two_bignums_fn: &F) -> Result<()> -where - F: Fn(usize) -> (BigUint, BigUint, U256, Vec), -{ - let (a, b, length, memory) = prepare_two_bignums_fn(1000); - - // Determine expected product. - let product = a * b; - let expected_product: Vec = biguint_to_mem_vec(product); - - // Output and scratch space locations (initialized as zeroes) follow a and b in memory. - let a_start_loc = 0.into(); - let b_start_loc = length; - let output_loc = length * 2; - - // Prepare stack. - let retdest = 0xDEADBEEFu32.into(); - let mut initial_stack: Vec = vec![length, a_start_loc, b_start_loc, output_loc, retdest]; - initial_stack.reverse(); - - // Prepare interpreter. - let mul_bignum = KERNEL.global_labels["mul_bignum"]; - let mut interpreter = Interpreter::new_with_kernel(mul_bignum, initial_stack); - interpreter.set_kernel_general_memory(memory); - - // Run mul function. - interpreter.run()?; - - // Determine actual product. - let new_memory = interpreter.get_kernel_general_memory(); - let output_location: usize = output_loc.try_into().unwrap(); - let actual_product: Vec<_> = - new_memory[output_location..output_location + expected_product.len()].into(); - - assert_eq!(actual_product, expected_product); - - Ok(()) -} - -#[test] -fn test_shr_bignum_all() -> Result<()> { - test_shr_bignum(&prepare_bignum_random)?; - test_shr_bignum(&prepare_bignum_max)?; - test_shr_bignum(&prepare_bignum_min)?; - - let test_data = test_data(); - for i in 0..test_data.len() { - test_shr_bignum(&|_| prepare_bignum_from_value(test_data[i].clone()))?; - } - - Ok(()) -} - -#[test] -fn test_iszero_bignum_all() -> Result<()> { - test_iszero_bignum(&prepare_bignum_random)?; - test_iszero_bignum(&prepare_bignum_max)?; - // No need to test for min, since it is zero. - - let test_data = test_data(); - for i in 0..test_data.len() { - if test_data[i] != 0u8.into() { - test_iszero_bignum(&|_| prepare_bignum_from_value(test_data[i].clone()))?; - } - } - - Ok(()) -} - -#[test] -fn test_cmp_bignum_all() -> Result<()> { - test_cmp_bignum(&prepare_two_bignums_random)?; - test_cmp_bignum(&prepare_two_bignums_max)?; - test_cmp_bignum(&prepare_two_bignums_min)?; - test_cmp_bignum(&prepare_two_bignums_diff)?; - - let test_data = test_data(); - for i in 0..test_data.len() { - for j in 0..i { - test_cmp_bignum(&|_| { - prepare_two_bignums_from_values(test_data[i].clone(), test_data[j].clone()) - })?; - } - } - - Ok(()) -} - -#[test] -fn test_add_bignum_all() -> Result<()> { - test_add_bignum(&prepare_two_bignums_random)?; - test_add_bignum(&prepare_two_bignums_max)?; - test_add_bignum(&prepare_two_bignums_min)?; - test_add_bignum(&prepare_two_bignums_diff)?; - test_add_bignum(&prepare_two_bignums_zero)?; - - let test_data = test_data(); - for i in 0..test_data.len() { - for j in 0..i { - test_add_bignum(&|_| { - prepare_two_bignums_from_values(test_data[i].clone(), test_data[j].clone()) - })?; - } - } - - Ok(()) -} - -#[test] -fn test_addmul_bignum_all() -> Result<()> { - test_addmul_bignum(&prepare_two_bignums_random)?; - test_addmul_bignum(&prepare_two_bignums_max)?; - test_addmul_bignum(&prepare_two_bignums_min)?; - test_addmul_bignum(&prepare_two_bignums_diff)?; - test_addmul_bignum(&prepare_two_bignums_zero)?; - - let test_data = test_data(); - for i in 0..test_data.len() { - for j in 0..i { - test_addmul_bignum(&|_| { - prepare_two_bignums_from_values(test_data[i].clone(), test_data[j].clone()) - })?; - } - } - - Ok(()) -} - -#[test] -fn test_mul_bignum_all() -> Result<()> { - test_mul_bignum(&prepare_two_bignums_random)?; - test_mul_bignum(&prepare_two_bignums_max)?; - test_mul_bignum(&prepare_two_bignums_min)?; - test_mul_bignum(&prepare_two_bignums_diff)?; - test_mul_bignum(&prepare_two_bignums_zero)?; - - let test_data = test_data(); - for i in 0..test_data.len() { - for j in 0..i { - test_mul_bignum(&|_| { - prepare_two_bignums_from_values(test_data[i].clone(), test_data[j].clone()) - })?; - } - } - - Ok(()) -} diff --git a/evm/src/cpu/kernel/tests/bignum/mod.rs b/evm/src/cpu/kernel/tests/bignum/mod.rs new file mode 100644 index 00000000..687347a5 --- /dev/null +++ b/evm/src/cpu/kernel/tests/bignum/mod.rs @@ -0,0 +1,356 @@ +use std::fs::File; +use std::io::{BufReader, BufRead}; +use std::path::PathBuf; + +use anyhow::Result; +use ethereum_types::U256; +use itertools::Itertools; +use num::{BigUint, One, Zero}; +use num_bigint::RandBigInt; +use plonky2_util::ceil_div_usize; +use rand::Rng; + +use crate::cpu::kernel::aggregator::KERNEL; +use crate::cpu::kernel::interpreter::Interpreter; +use crate::util::{biguint_to_mem_vec, mem_vec_to_biguint}; + +const BIGNUM_LIMB_BITS: usize = 128; +const MINUS_ONE: U256 = U256::MAX; + +const TEST_DATA_BIGNUM_INPUTS: &str = "bignum_inputs"; +const TEST_DATA_U128_INPUTS: &str = "u128_inputs"; +const TEST_DATA_SHR_OUTPUTS: &str = "shr_outputs"; +const TEST_DATA_ISZERO_OUTPUTS: &str = "iszero_outputs"; +const TEST_DATA_CMP_OUTPUTS: &str = "cmp_outputs"; +const TEST_DATA_ADD_OUTPUTS: &str = "add_outputs"; +const TEST_DATA_ADDMUL_OUTPUTS: &str = "addmul_outputs"; +const TEST_DATA_MUL_OUTPUTS: &str = "mul_outputs"; + +const BIT_SIZES_TO_TEST: [usize; 4] = [128, 256, 512, 1000]; + +fn full_path(filename: &str) -> PathBuf { + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.push("src/cpu/kernel/tests/bignum/test_data"); + path.push(filename); + path +} + +fn test_data(filename: &str) -> Vec { + let file = File::open(full_path(filename)).unwrap(); + let lines = BufReader::new(file).lines(); + lines.map(|line| BigUint::parse_bytes(&line.unwrap().as_bytes(), 10).unwrap()).collect() +} + +fn test_data_u128(filename: &str) -> Vec { + let file = File::open(full_path(filename)).unwrap(); + let lines = BufReader::new(file).lines(); + lines.map(|line| line.unwrap().parse::().unwrap()).collect() +} + +fn test_data_u256(filename: &str) -> Vec { + let file = File::open(full_path(filename)).unwrap(); + let lines = BufReader::new(file).lines(); + lines.map(|line| U256::from_dec_str(&line.unwrap()).unwrap()).collect() +} + +// Convert each biguint to a vector of bignum limbs, pad to the given length, and concatenate. +fn pad_bignums(biguints: &[BigUint], length: usize) -> Vec { + biguints + .iter() + .flat_map(|biguint| { + biguint_to_mem_vec(biguint.clone()) + .into_iter() + .pad_using(length, |_| U256::zero()) + }) + .collect() +} + +fn gen_bignum(bit_size: usize) -> BigUint { + let mut rng = rand::thread_rng(); + rng.gen_biguint(bit_size as u64) +} + +fn max_bignum(bit_size: usize) -> BigUint { + (BigUint::one() << bit_size) - BigUint::one() +} + +fn bignum_len(a: &BigUint) -> usize { + ceil_div_usize(a.bits() as usize, BIGNUM_LIMB_BITS) +} + +fn run_test(fn_label: &str, memory: Vec, stack: Vec) -> Result<(Vec, Vec)> { + let fn_label = KERNEL.global_labels[fn_label]; + let retdest = 0xDEADBEEFu32.into(); + + let mut initial_stack: Vec = stack; + initial_stack.push(retdest); + initial_stack.reverse(); + + let mut interpreter = Interpreter::new_with_kernel(fn_label, initial_stack); + interpreter.set_kernel_general_memory(memory); + interpreter.run()?; + + let new_memory = interpreter.get_kernel_general_memory(); + + Ok((new_memory, interpreter.stack().to_vec())) +} + +fn test_shr_bignum(input: BigUint, expected_output: BigUint) -> Result<()> +{ + let len = bignum_len(&input); + let memory = biguint_to_mem_vec(input.clone()); + + let input_start_loc = 0; + let (new_memory, _new_stack) = run_test("shr_bignum", memory, vec![len.into(), input_start_loc.into()])?; + + let output = mem_vec_to_biguint(&new_memory[input_start_loc..input_start_loc+len]); + assert_eq!(output, expected_output); + + Ok(()) +} + +fn test_iszero_bignum(input: BigUint, expected_output: U256) -> Result<()> +{ + let len = bignum_len(&input); + let memory = biguint_to_mem_vec(input.clone()); + + let input_start_loc = 0; + let (_new_memory, new_stack) = run_test("iszero_bignum", memory, vec![len.into(), input_start_loc.into()])?; + + let output = new_stack[0]; + assert_eq!(output, expected_output); + + Ok(()) +} + +fn test_cmp_bignum(a: BigUint, b: BigUint, expected_output: U256) -> Result<()> +{ + let len = bignum_len(&a).max(bignum_len(&b)); + let memory = pad_bignums(&[a.clone(), b.clone()], len); + + let a_start_loc = 0; + let b_start_loc = len; + let (_new_memory, new_stack) = run_test("cmp_bignum", memory, vec![len.into(), a_start_loc.into(), b_start_loc.into()])?; + + let output = new_stack[0]; + assert_eq!(output, expected_output); + + Ok(()) +} + +fn test_add_bignum(a: BigUint, b: BigUint, expected_output: BigUint) -> Result<()> +{ + let len = bignum_len(&a).max(bignum_len(&b)); + let memory = pad_bignums(&[a.clone(), b.clone()], len); + + let a_start_loc = 0; + let b_start_loc = len; + let (mut new_memory, new_stack) = run_test("add_bignum", memory, vec![len.into(), a_start_loc.into(), b_start_loc.into()])?; + + // Determine actual sum, appending the final carry if nonzero. + let carry_limb = new_stack[0]; + if carry_limb > 0.into() { + new_memory[len] = carry_limb; + } + let output = mem_vec_to_biguint(&new_memory[a_start_loc..a_start_loc+len]); + assert_eq!(output, expected_output); + + Ok(()) +} + +fn test_addmul_bignum(a: BigUint, b: BigUint, c: u128, expected_output: BigUint) -> Result<()> +{ + let len = bignum_len(&a).max(bignum_len(&b)); + let mut memory = pad_bignums(&[a.clone(), b.clone()], len); + memory.splice(len..len, vec![0.into(); 2].iter().cloned()); + + let a_start_loc = 0; + let b_start_loc = len + 2; + let (mut new_memory, new_stack) = run_test("addmul_bignum", memory, vec![len.into(), a_start_loc.into(), b_start_loc.into(), c.into()])?; + + // Determine actual sum, appending the final carry if nonzero. + let carry_limb = new_stack[0]; + if carry_limb > 0.into() { + new_memory[len] = carry_limb; + } + let output = mem_vec_to_biguint(&new_memory[a_start_loc..a_start_loc+len]); + assert_eq!(output, expected_output); + + Ok(()) +} + +fn test_mul_bignum(a: BigUint, b: BigUint, expected_output: BigUint) -> Result<()> +{ + let len = bignum_len(&a).max(bignum_len(&b)); + let output_len = len * 2; + let memory = pad_bignums(&[a.clone(), b.clone()], len); + + let a_start_loc = 0; + let b_start_loc = len; + let output_start_loc = 2 * len; + let (new_memory, _new_stack) = run_test("mul_bignum", memory, vec![len.into(), a_start_loc.into(), b_start_loc.into(), output_start_loc.into()])?; + + let output = mem_vec_to_biguint(&new_memory[output_start_loc..output_start_loc+output_len]); + assert_eq!(output, expected_output); + + Ok(()) +} + +#[test] +fn test_shr_bignum_all() -> Result<()> { + for bit_size in BIT_SIZES_TO_TEST { + let input = gen_bignum(bit_size); + let output = input.clone() >> 1; + test_shr_bignum(input, output)?; + + let input = max_bignum(bit_size); + let output = input.clone() >> 1; + test_shr_bignum(input, output)?; + } + + let inputs = test_data(TEST_DATA_BIGNUM_INPUTS); + let shr_outputs = test_data(TEST_DATA_SHR_OUTPUTS); + for (input, output) in inputs.iter().zip(shr_outputs.iter()) { + test_shr_bignum(input.clone(), output.clone())?; + } + + Ok(()) +} + +#[test] +fn test_iszero_bignum_all() -> Result<()> { + for bit_size in BIT_SIZES_TO_TEST { + let input = gen_bignum(bit_size); + let output = input.is_zero() as u8; + test_iszero_bignum(input, output.into())?; + + let input = max_bignum(bit_size); + let output = 0; + test_iszero_bignum(input, output.into())?; + } + + let inputs = test_data(TEST_DATA_BIGNUM_INPUTS); + let iszero_outputs = test_data_u256(TEST_DATA_ISZERO_OUTPUTS); + let mut iszero_outputs_iter = iszero_outputs.iter(); + for input in inputs { + let output = iszero_outputs_iter.next().unwrap(); + test_iszero_bignum(input.clone(), *output)?; + } + + Ok(()) +} + +#[test] +fn test_cmp_bignum_all() -> Result<()> { + for bit_size in BIT_SIZES_TO_TEST { + let a = gen_bignum(bit_size); + let b = gen_bignum(bit_size); + let output = if a < b { MINUS_ONE } else if a == b { 0.into() } else { 1.into() }; + test_cmp_bignum(a, b, output)?; + + let a = max_bignum(bit_size); + let b = max_bignum(bit_size); + let output = 0.into(); + test_cmp_bignum(a, b, output)?; + } + + let inputs = test_data(TEST_DATA_BIGNUM_INPUTS); + let cmp_outputs = test_data_u256(TEST_DATA_CMP_OUTPUTS); + let mut cmp_outputs_iter = cmp_outputs.iter(); + for a in inputs.clone() { + for b in inputs.clone() { + let output = cmp_outputs_iter.next().unwrap(); + test_cmp_bignum(a.clone(), b.clone(), *output)?; + } + } + + Ok(()) +} + +#[test] +fn test_add_bignum_all() -> Result<()> { + for bit_size in BIT_SIZES_TO_TEST { + let a = gen_bignum(bit_size); + let b = gen_bignum(bit_size); + let output = a.clone() + b.clone(); + test_add_bignum(a, b, output)?; + + let a = max_bignum(bit_size); + let b = max_bignum(bit_size); + let output = a.clone() + b.clone(); + test_add_bignum(a, b, output)?; + } + + let inputs = test_data(TEST_DATA_BIGNUM_INPUTS); + let add_outputs = test_data(TEST_DATA_ADD_OUTPUTS); + let mut add_outputs_iter = add_outputs.iter(); + for a in inputs.clone() { + for b in inputs.clone() { + let output = add_outputs_iter.next().unwrap(); + test_add_bignum(a.clone(), b.clone(), output.clone())?; + } + } + + Ok(()) +} + +#[test] +fn test_addmul_bignum_all() -> Result<()> { + let mut rng = rand::thread_rng(); + + for bit_size in BIT_SIZES_TO_TEST { + let a = gen_bignum(bit_size); + let b = gen_bignum(bit_size); + let c: u128 = rng.gen(); + let output = a.clone() + b.clone() * c; + test_addmul_bignum(a, b, c, output)?; + + let a = max_bignum(bit_size); + let b = max_bignum(bit_size); + let c: u128 = rng.gen(); + let output = a.clone() + b.clone() * c; + test_addmul_bignum(a, b, c, output)?; + } + + let inputs = test_data(TEST_DATA_BIGNUM_INPUTS); + let u128_inputs = test_data_u128(TEST_DATA_U128_INPUTS); + let addmul_outputs = test_data(TEST_DATA_ADDMUL_OUTPUTS); + let mut addmul_outputs_iter = addmul_outputs.iter(); + for a in inputs.clone() { + for b in inputs.clone() { + for c in u128_inputs.clone() { + let output = addmul_outputs_iter.next().unwrap(); + test_addmul_bignum(a.clone(), b.clone(), c, output.clone())?; + } + } + } + + Ok(()) +} + +#[test] +fn test_mul_bignum_all() -> Result<()> { + for bit_size in BIT_SIZES_TO_TEST { + let a = gen_bignum(bit_size); + let b = gen_bignum(bit_size); + let output = a.clone() * b.clone(); + test_mul_bignum(a, b, output)?; + + let a = max_bignum(bit_size); + let b = max_bignum(bit_size); + let output = a.clone() * b.clone(); + test_mul_bignum(a, b, output)?; + } + + let inputs = test_data(TEST_DATA_BIGNUM_INPUTS); + let mul_outputs = test_data(TEST_DATA_MUL_OUTPUTS); + let mut mul_outputs_iter = mul_outputs.iter(); + for a in inputs.clone() { + for b in inputs.clone() { + let output = mul_outputs_iter.next().unwrap(); + test_mul_bignum(a.clone(), b.clone(), output.clone())?; + } + } + + Ok(()) +} diff --git a/evm/src/cpu/kernel/tests/bignum/test_data/add_outputs b/evm/src/cpu/kernel/tests/bignum/test_data/add_outputs new file mode 100644 index 00000000..36ebe049 --- /dev/null +++ b/evm/src/cpu/kernel/tests/bignum/test_data/add_outputs @@ -0,0 +1,225 @@ +0 +1 +21 +908 +1267650597867046177654064545792 +340282366920938463463374607431768211455 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +1 +2 +22 +909 +1267650597867046177654064545793 +340282366920938463463374607431768211456 +57896044618658097611351864738157061705262361561497619362091104892532012613633 +115792089237105570840234253759177109864155645142784332660520492325483608801281 +231583736816786089484927226016147767929578972263620494977377884571370600267776 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049793 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348288 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780160 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103233 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369217 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046272 +21 +22 +42 +929 +1267650597867046177654064545813 +340282366920938463463374607431768211476 +57896044618658097611351864738157061705262361561497619362091104892532012613653 +115792089237105570840234253759177109864155645142784332660520492325483608801301 +231583736816786089484927226016147767929578972263620494977377884571370600267796 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049813 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348308 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780180 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103253 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369237 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046292 +908 +909 +929 +1816 +1267650597867046177654064546700 +340282366920938463463374607431768212363 +57896044618658097611351864738157061705262361561497619362091104892532012614540 +115792089237105570840234253759177109864155645142784332660520492325483608802188 +231583736816786089484927226016147767929578972263620494977377884571370600268683 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998050700 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486349195 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690781067 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387104140 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375370124 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957047179 +1267650597867046177654064545792 +1267650597867046177654064545793 +1267650597867046177654064545813 +1267650597867046177654064546700 +2535301195734092355308129091584 +340282368188589061330420785085832757247 +57896044618658097611351864738157061705262361562765269959958151070186077159424 +115792089237105570840234253759177109864155645144051983258387538503137673347072 +231583736816786089484927226016147767929578972264888145575244930749024664813567 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725447442614227457227324739062595584 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851379715837692741036504647550894079 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756017613817472060411970538755325951 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459868939503685406252196573451649024 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059367521063656309566056683439915008 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571754105966758923615108084021592063 +340282366920938463463374607431768211455 +340282366920938463463374607431768211456 +340282366920938463463374607431768211476 +340282366920938463463374607431768212363 +340282368188589061330420785085832757247 +680564733841876926926749214863536422910 +57896044618658097611351864738157061705602643928418557825554479499963780825087 +115792089237105570840234253759177109864495927509705271123983866932915377012735 +231583736816786089484927226016147767929919254630541433440841259178802368479230 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656433007813095902093053555754516766261247 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352969133745369125558337364934425254559742 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107569038383267105337656740400316458991614 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244438742234592791551002580626351155314687 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359572341733174351521905894486461143580671 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998595854119759254624519943537861725257726 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +57896044618658097611351864738157061705262361561497619362091104892532012613633 +57896044618658097611351864738157061705262361561497619362091104892532012613653 +57896044618658097611351864738157061705262361561497619362091104892532012614540 +57896044618658097611351864738157061705262361562765269959958151070186077159424 +57896044618658097611351864738157061705602643928418557825554479499963780825087 +115792089237316195222703729476314123410524723122995238724182209785064025227264 +173688133855763668451586118497334171569418006704281952022611597218015621414912 +289479781435444187096279090754304829634841333825118114339468989463902612881407 +3273390607896141870013189696827599152216642046043064789482248405676250539586401155309462588318799202567027652361355087007672582991681286039617010663424 +5027927973729236057982426364448826617555638513633071601633370220421967636306804394074875752581912318823441521134057891212939945806456965095219525498961919 +13407807929942597099574024997867385471458758537929012740010782671329620832395892888572752773084019014537559577489812491117577843786236284470685416703393791 +26815615859885194199148049995734770942917517075858043397979502765092926124329972428655111861232797616170839264946949360821429169472449630310911451399716864 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356940333001073316904952470628102164776064494420927751032420533624771561387982848 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463796730242309831072892700701204289449703517933314335935523147673822961969659903 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +115792089237105570840234253759177109864155645142784332660520492325483608801281 +115792089237105570840234253759177109864155645142784332660520492325483608801301 +115792089237105570840234253759177109864155645142784332660520492325483608802188 +115792089237105570840234253759177109864155645144051983258387538503137673347072 +115792089237105570840234253759177109864495927509705271123983866932915377012735 +173688133855763668451586118497334171569418006704281952022611597218015621414912 +231584178474211141680468507518354219728311290285568665321040984650967217602560 +347375826053891660325161479775324877793734617406404827637898376896854209069055 +3273390607896141870013189696827599152216642046043064789482248405676250539644297199927910061547681591588047700520248370588959296290110673472568606851072 +5027927973729236057982426364448826617555638513633071601633370220421967636306862290119494200055141201212462541182216784496521232519755394482652477095149567 +13407807929942597099574024997867385471458758537929012740010782671329620832395950784617371220557247896926580597537971384401159130499534713858118368299581439 +26815615859885194199148049995734770942917517075858043397979502765092926124330030324699730308706026498559860284995108254105010456185748059698344402995904512 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356998229045691764378181353017123184824223387704509037745718963012204512984170496 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463854626286928278546121583090225309497862411216895622648821577061255913565847551 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +231583736816786089484927226016147767929578972263620494977377884571370600267776 +231583736816786089484927226016147767929578972263620494977377884571370600267796 +231583736816786089484927226016147767929578972263620494977377884571370600268683 +231583736816786089484927226016147767929578972264888145575244930749024664813567 +231583736816786089484927226016147767929919254630541433440841259178802368479230 +289479781435444187096279090754304829634841333825118114339468989463902612881407 +347375826053891660325161479775324877793734617406404827637898376896854209069055 +463167473633572178969854452032295535859157944527240989954755769142741200535550 +3273390607896141870013189696827599152216642046043064789482248405676250539760088847507590580192374563845018358585671697709795458606968065718455598317567 +5027927973729236057982426364448826617555638513633071601633370220421967636306978081767073880573785894184719511840282207823642068682072251874898364086616062 +13407807929942597099574024997867385471458758537929012740010782671329620832396066576264950901075892589898837568196036807728279966661851571250364255291047934 +26815615859885194199148049995734770942917517075858043397979502765092926124330146116347309989224671191532117255653173677432131292348064917090590289987371007 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322357114020693271444896826045989380155482288811031629873908035820404450399975636991 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463970417934507959064766276062482280155927834544016458811138434453501800557314046 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049793 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049813 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998050700 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725447442614227457227324739062595584 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656433007813095902093053555754516766261247 +3273390607896141870013189696827599152216642046043064789482248405676250539586401155309462588318799202567027652361355087007672582991681286039617010663424 +3273390607896141870013189696827599152216642046043064789482248405676250539644297199927910061547681591588047700520248370588959296290110673472568606851072 +3273390607896141870013189696827599152216642046043064789482248405676250539760088847507590580192374563845018358585671697709795458606968065718455598317567 +6546781215792283740026379393655198304433284092086129578964496811352501079057010221381608981414894675657741181312185450892349927259180362294169996099584 +5031201364337132199852439554145654216707855155679114666422852468827643886846275003140947898975008414296532234663008721576824623150724464171474078484398079 +13411081320550493241444038187564213070610975179975055804800264919735297082935363497638824919477115110010650291018763321481462521130503783546939969688829951 +26818889250493090341018063185431598542069733717904086462768985013498602374869443037721184007625893711643929978475900191185313846816717129387166004385153024 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094859873731529946340457125253265606438475403785866280608383688705623749572896410942067145463298048566101192878305015324784812428376688032701026114373419008 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988312365191525626829590504228669795829923743060941349315981180118158171906003267339308381977465988796174295002978654348297199013279790646750077514955096063 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348288 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348308 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486349195 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851379715837692741036504647550894079 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352969133745369125558337364934425254559742 +5027927973729236057982426364448826617555638513633071601633370220421967636306804394074875752581912318823441521134057891212939945806456965095219525498961919 +5027927973729236057982426364448826617555638513633071601633370220421967636306862290119494200055141201212462541182216784496521232519755394482652477095149567 +5027927973729236057982426364448826617555638513633071601633370220421967636306978081767073880573785894184719511840282207823642068682072251874898364086616062 +5031201364337132199852439554145654216707855155679114666422852468827643886846275003140947898975008414296532234663008721576824623150724464171474078484398079 +10055855947458472115964852728897653235111277027266143203266740440843935272613492996060514188968601933917406728144705257702756896374189747980653986972696574 +18435735903671833157556451362316212089014397051562084341644152891751588468702581490558391209470708629631524784500459857607394794353969067356119878177128446 +31843543833614430257130476360183597560473155589491114999612872985514893760636661030640750297619487231264804471957596727311246120040182413196345912873451519 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604099884528314651286256569538428017605456878825657453309145227576677640040958663628934986711753291642085722067371786711860910744701600153316510206022861717503 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060993337019774646966745702917403421794848327164932528377852825068090174463291770485332227948267459582315795169496460350884423131286503255930559257423443394558 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780160 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780180 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690781067 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756017613817472060411970538755325951 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107569038383267105337656740400316458991614 +13407807929942597099574024997867385471458758537929012740010782671329620832395892888572752773084019014537559577489812491117577843786236284470685416703393791 +13407807929942597099574024997867385471458758537929012740010782671329620832395950784617371220557247896926580597537971384401159130499534713858118368299581439 +13407807929942597099574024997867385471458758537929012740010782671329620832396066576264950901075892589898837568196036807728279966661851571250364255291047934 +13411081320550493241444038187564213070610975179975055804800264919735297082935363497638824919477115110010650291018763321481462521130503783546939969688829951 +18435735903671833157556451362316212089014397051562084341644152891751588468702581490558391209470708629631524784500459857607394794353969067356119878177128446 +26815615859885194199148049995734770942917517075858025480021565342659241664791669985056268229972815325345642840856214457512032692333748386731585769381560318 +40223423789827791298722074993602156414376275613787056137990285436422546956725749525138627318121593926978922528313351327215884018019961732571811804077883391 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604108264408270864647298161137061436164310781945681749250283604989128547694154752717429484588773793748781436185428142466460815382599579932635885671914066149375 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581061001716899730860327787294516036840353702230284956824318991202480541082116487859573826725825287961689011509287552816105484327769184483035249934723314647826430 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103233 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103253 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387104140 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459868939503685406252196573451649024 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244438742234592791551002580626351155314687 +26815615859885194199148049995734770942917517075858043397979502765092926124329972428655111861232797616170839264946949360821429169472449630310911451399716864 +26815615859885194199148049995734770942917517075858043397979502765092926124330030324699730308706026498559860284995108254105010456185748059698344402995904512 +26815615859885194199148049995734770942917517075858043397979502765092926124330146116347309989224671191532117255653173677432131292348064917090590289987371007 +26818889250493090341018063185431598542069733717904086462768985013498602374869443037721184007625893711643929978475900191185313846816717129387166004385153024 +31843543833614430257130476360183597560473155589491114999612872985514893760636661030640750297619487231264804471957596727311246120040182413196345912873451519 +40223423789827791298722074993602156414376275613787056137990285436422546956725749525138627318121593926978922528313351327215884018019961732571811804077883391 +53631231719770388398296099991469541885835034151716086795959005530185852248659829065220986406270372528612202215770488196919735343706175078412037838774206464 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604121672216200807244397735162059303549782240704219678280941573709222310999446686796969566947861942527383069465115599603330519233925266145981725897948762472448 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581061015124707660802924886868541034707739173689043494753349649171200634845421779793653366808184376110467613142567240273242354031620510169248595774949349344149503 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369217 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369237 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375370124 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059367521063656309566056683439915008 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359572341733174351521905894486461143580671 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356940333001073316904952470628102164776064494420927751032420533624771561387982848 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356998229045691764378181353017123184824223387704509037745718963012204512984170496 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322357114020693271444896826045989380155482288811031629873908035820404450399975636991 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094859873731529946340457125253265606438475403785866280608383688705623749572896410942067145463298048566101192878305015324784812428376688032701026114373419008 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604099884528314651286256569538428017605456878825657453309145227576677640040958663628934986711753291642085722067371786711860910744701600153316510206022861717503 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604108264408270864647298161137061436164310781945681749250283604989128547694154752717429484588773793748781436185428142466460815382599579932635885671914066149375 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604121672216200807244397735162059303549782240704219678280941573709222310999446686796969566947861942527383069465115599603330519233925266145981725897948762472448 +21430172143725344039741447416747135734328099194269775938858685112579378184657786065906763159178676625205218492566825428477050725853377832065983208189713200681844100397174224127137557678646374287640475087188412914436146644713764873912909317614682237526728015428718464118732506826116885039758058750738432 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824629198276151174244463087285660418287344529756165187857520911105123842660034918703411836307538943107430287596439419222071804002615797677806638572665083165692141839780886307603102541747070094713562715543794785904326970568977820621271154145831782622467599830140102357487631119091729219499088809459332415487 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046272 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046292 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957047179 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571754105966758923615108084021592063 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998595854119759254624519943537861725257726 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463796730242309831072892700701204289449703517933314335935523147673822961969659903 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463854626286928278546121583090225309497862411216895622648821577061255913565847551 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463970417934507959064766276062482280155927834544016458811138434453501800557314046 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988312365191525626829590504228669795829923743060941349315981180118158171906003267339308381977465988796174295002978654348297199013279790646750077514955096063 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060993337019774646966745702917403421794848327164932528377852825068090174463291770485332227948267459582315795169496460350884423131286503255930559257423443394558 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581061001716899730860327787294516036840353702230284956824318991202480541082116487859573826725825287961689011509287552816105484327769184483035249934723314647826430 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581061015124707660802924886868541034707739173689043494753349649171200634845421779793653366808184376110467613142567240273242354031620510169248595774949349344149503 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824629198276151174244463087285660418287344529756165187857520911105123842660034918703411836307538943107430287596439419222071804002615797677806638572665083165692141839780886307603102541747070094713562715543794785904326970568977820621271154145831782622467599830140102357487631119091729219499088809459332415487 +70149324220868077495255175920561715987048031760661657648151596049581927701126644407314161773169938523306300574636470765864723972756401953860971729649236966380158623144886433123904089438954731413136105939102963525135105941885179620757765851918707538235369974386271618715130954505741977781211162121976618183601835461375440982077945936461543052837790612502383395739504991310927477668395382345950562697672932264775996511143505676632322113137860859914092542 diff --git a/evm/src/cpu/kernel/tests/bignum/test_data/addmul_outputs b/evm/src/cpu/kernel/tests/bignum/test_data/addmul_outputs new file mode 100644 index 00000000..397c7451 --- /dev/null +++ b/evm/src/cpu/kernel/tests/bignum/test_data/addmul_outputs @@ -0,0 +1,1350 @@ +0 +0 +0 +0 +0 +0 +0 +1 +21 +908 +1267650597867046177654064545792 +340282366920938463463374607431768211455 +0 +21 +441 +19068 +26620662555207969730735355461632 +7145929705339707732730866756067132440555 +0 +908 +19068 +824464 +1151026742863277929309890607579136 +308976389164212124824744143548045536001140 +0 +1267650597867046177654064545792 +26620662555207969730735355461632 +1151026742863277929309890607579136 +1606938038272679619211255036084048932956190504430095264907264 +431359145870941220571487096504865044588697904564591140391738786447360 +0 +340282366920938463463374607431768211455 +7145929705339707732730866756067132440555 +308976389164212124824744143548045536001140 +431359145870941220571487096504865044588697904564591140391738786447360 +115792089237316195423570985008687907852589419931798687112530834793049593217025 +0 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +1215816936991820049838389159501298295810509592791450006603913202743172264886272 +52569608513741552631107493182246612028378224297839838380778723242419067453177856 +73391955574979118963811141843059488536193514605218060347731553038824318137413435829926783487818828867436544 +19701003098197239571963727475337245584161626291901231402719522479678259504890677218990119895590117915143388591554560 +0 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +2431633873979216987644919328942719307147268547998470985870930338835155784826880 +105139217027291858322932702413332815756653325789648174055752607031539116791562240 +146783911149691239803259475393272332038744581223672095908357420057841712239442615794649035123910216788213760 +39402006196322807380529480735708200350692396090822410401547663254352517428719749608020233606624972587007562114662400 +0 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +4863258473152507879183471746339103126521158417536030394524935575998782605623275 +210278033029641769252313921222662173280057706815367409439459119190804505043139700 +293567262432083559770702660509494961636846893913475830448684457955877331972488384611363806317219648949452800 +78803862104411649792976274791681038936454943300723566886694079153850261012036590002656572187311458765011955822362625 +0 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +68741202765818979270276983633379582196549482966904360579127216519201261330098607324506894304856394094406282403777947234369674236221393804088784959045632 +2972238671969696817971976244719460030212710977807102828849881552354035489891882640507250477562362182748614496315732194705126866975667884481553178229211136 +4149515561151917970063980879655710938513649460124350952720371065270297197065154634382680097543307069927884450339928718724097725668943949230978441358030208342019760039438410280075264 +1113877103911668754551067286547922686738237475419584309931192581897577662915063323503306740447008536028968181678028580322422866333819711284625174374608617279642589745120484326564854874767360 +0 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +105586487448313957217630953653425358968668408786294503634300774628861320362441676458635398984170320306132770645519405205878947411928992353796866863213314027 +4565358600146146340648043138919534568740519770378829014283100160143146613766525820211473441791745277998502654577696186997051630953882145583216910085604244596 +6373655901930312136397229380018411440828683949391920950832693445711366448193584697763678864931677968612065262908033170282412527802037703004824976134384286640214222530054133889372258304 +1710915231608582551713494414139930175751260546116444122900349352360496966554854730076753484481830650675467827629295222707109502155201699203484369755223655341193278275893163301956243837193027585 +0 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +281563966528794539091054524955215094900633929296509267540226436097922037480312534843090816414714560916129249828990251803876343269504358060681650578506383339 +12174289600387878166413214698063586008084552752439543567929790665567295715815418173215545776407658157706921849748721363710462842319521767576139939299228384372 +16996415738478256005382065682640742151192912704409604594012987116129634408058546371285779101609491343355313613863898166638327059654603396304113335697353121717251389843622698066460540928 +4562440617622195218641171605585119131739514871918667547682857357314343535508689562160604455918497575074715174882382908134196095677901105600185199282794955018371204524886410100925712980030521345 +0 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +563127933057589078182109049910430189801267858593018911357569558066951448610928205184820357265838911550428123265590126067657221108914838323326397307129167872 +24348579200775756332826429396127172016169105504879103405365388510704376920891562395610327828446749127989939805959801641401559846042603485599065178803489734656 +33992831476956512010764131365281484302385825408819231901736066162392911122587750794642859557837487570646738733764326406607430768230396539092082721200286809873288301231428402460695199744 +9124881235244390437282343211170238263479029743837341192530852050551013988199468564099149809149237792502394782872367659707645708326849200364829008985690446628655225628506036591091211274089922560 +0 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +225016807509116112417285197875844925210445041539832647358016193682083470938906753692021013171376104564654794171951666999009032621460467236692823685991988607159363054170329353334944355625786930020224988415478335601579539769494531176085547834954163494030644162001543873246691321674227292917459616882753536 +9729298153251306194042617127203199623384957034198478276241843041111037695834634873921670474267119187843169195625338744528581029537433535757956376518129793109557221580317097753720451186105453926588775689583539463154010576700049252756460830197065735837134519004638182709904558099057065808050158672835248128 +13582985265193575509847153720290630277475301176695966793104558898916525902171099726111653252346386417687634059875171486934990855171785554727726817192028731914702681172768151028934363876033198780003232825417916826555570603003610443324900765322801514628836373961563717819815659178099324514051673737887522648522145975473923735339139072 +3646154850295010964902624396817474390399390616036693719739415376725561063085178919082942505698777176089060633115597677023110409583667009527018497076154392047301826729011247840192495744913649306569979494349478121435366144715292958165239232610420731738086890347478323006048396719686780691510330825043607290550999833104265740262684222585569280 +0 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +736567904319114813700179347165898017864004333486947405305591758520610240861829766276798698618284354494716156033682943041579601713942220515540203161316988146991665543021307547800992939109024679837929112360581117013918612389794386017956541445146429151471384731055851996508875022310290766702717202280754490927819272344442130311818432332846202054796801431275025655264802408764738515518151514632480908325565788780147963367006809604639382187947539029097971691 +31847793196274107182845849867935019058119806419340392572260824606510195176311496560920629445019152089581060460884957727702584683631406487052881165260753582736592014907778440638252456605285448061563792096352745440411338097615871547824025696771093222358857968371367314896669453345606857912669867603377384655355233299464450205863387455153540545988356938076082061665735266055161074861451503585061555464743511248208302416059151577191074239364588830400998014068 +44462416394276340862910922260389321581298853470913371563358965890746390942505208917810214508921403677924050484037361854923909199530783769557857398908416797467991642660044081596444758567725905941578862500220928052627591160031402858547990440510112144073496748573294083122100295594485512238065152913601534980743295758670057701269862152855527112109603873427804287879276629501582896265202691196110634325565999430887153483257613158570830305101308846059434951620873330091758706311542341632 +11935289041890653422458560211344367565999989567726224393815132782921219808519438180124970259072038417888105302535754774032670805811336900569676094726678661851388189281957447472598923409448779291182901295823514011338832830575108282476521982723289897702706625317681157972521881629518687524749107700488703863037130875637878556278141428758998783243913325146240393321801800775493463196094645471464263521615496507631433158100292031999009575957202146963989209941350094442798986370318517904347234305 +1 +1 +1 +1 +1 +1 +1 +2 +22 +909 +1267650597867046177654064545793 +340282366920938463463374607431768211456 +1 +22 +442 +19069 +26620662555207969730735355461633 +7145929705339707732730866756067132440556 +1 +909 +19069 +824465 +1151026742863277929309890607579137 +308976389164212124824744143548045536001141 +1 +1267650597867046177654064545793 +26620662555207969730735355461633 +1151026742863277929309890607579137 +1606938038272679619211255036084048932956190504430095264907265 +431359145870941220571487096504865044588697904564591140391738786447361 +1 +340282366920938463463374607431768211456 +7145929705339707732730866756067132440556 +308976389164212124824744143548045536001141 +431359145870941220571487096504865044588697904564591140391738786447361 +115792089237316195423570985008687907852589419931798687112530834793049593217026 +1 +57896044618658097611351864738157061705262361561497619362091104892532012613633 +1215816936991820049838389159501298295810509592791450006603913202743172264886273 +52569608513741552631107493182246612028378224297839838380778723242419067453177857 +73391955574979118963811141843059488536193514605218060347731553038824318137413435829926783487818828867436545 +19701003098197239571963727475337245584161626291901231402719522479678259504890677218990119895590117915143388591554561 +1 +115792089237105570840234253759177109864155645142784332660520492325483608801281 +2431633873979216987644919328942719307147268547998470985870930338835155784826881 +105139217027291858322932702413332815756653325789648174055752607031539116791562241 +146783911149691239803259475393272332038744581223672095908357420057841712239442615794649035123910216788213761 +39402006196322807380529480735708200350692396090822410401547663254352517428719749608020233606624972587007562114662401 +1 +231583736816786089484927226016147767929578972263620494977377884571370600267776 +4863258473152507879183471746339103126521158417536030394524935575998782605623276 +210278033029641769252313921222662173280057706815367409439459119190804505043139701 +293567262432083559770702660509494961636846893913475830448684457955877331972488384611363806317219648949452801 +78803862104411649792976274791681038936454943300723566886694079153850261012036590002656572187311458765011955822362626 +1 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049793 +68741202765818979270276983633379582196549482966904360579127216519201261330098607324506894304856394094406282403777947234369674236221393804088784959045633 +2972238671969696817971976244719460030212710977807102828849881552354035489891882640507250477562362182748614496315732194705126866975667884481553178229211137 +4149515561151917970063980879655710938513649460124350952720371065270297197065154634382680097543307069927884450339928718724097725668943949230978441358030208342019760039438410280075265 +1113877103911668754551067286547922686738237475419584309931192581897577662915063323503306740447008536028968181678028580322422866333819711284625174374608617279642589745120484326564854874767361 +1 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348288 +105586487448313957217630953653425358968668408786294503634300774628861320362441676458635398984170320306132770645519405205878947411928992353796866863213314028 +4565358600146146340648043138919534568740519770378829014283100160143146613766525820211473441791745277998502654577696186997051630953882145583216910085604244597 +6373655901930312136397229380018411440828683949391920950832693445711366448193584697763678864931677968612065262908033170282412527802037703004824976134384286640214222530054133889372258305 +1710915231608582551713494414139930175751260546116444122900349352360496966554854730076753484481830650675467827629295222707109502155201699203484369755223655341193278275893163301956243837193027586 +1 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780160 +281563966528794539091054524955215094900633929296509267540226436097922037480312534843090816414714560916129249828990251803876343269504358060681650578506383340 +12174289600387878166413214698063586008084552752439543567929790665567295715815418173215545776407658157706921849748721363710462842319521767576139939299228384373 +16996415738478256005382065682640742151192912704409604594012987116129634408058546371285779101609491343355313613863898166638327059654603396304113335697353121717251389843622698066460540929 +4562440617622195218641171605585119131739514871918667547682857357314343535508689562160604455918497575074715174882382908134196095677901105600185199282794955018371204524886410100925712980030521346 +1 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103233 +563127933057589078182109049910430189801267858593018911357569558066951448610928205184820357265838911550428123265590126067657221108914838323326397307129167873 +24348579200775756332826429396127172016169105504879103405365388510704376920891562395610327828446749127989939805959801641401559846042603485599065178803489734657 +33992831476956512010764131365281484302385825408819231901736066162392911122587750794642859557837487570646738733764326406607430768230396539092082721200286809873288301231428402460695199745 +9124881235244390437282343211170238263479029743837341192530852050551013988199468564099149809149237792502394782872367659707645708326849200364829008985690446628655225628506036591091211274089922561 +1 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369217 +225016807509116112417285197875844925210445041539832647358016193682083470938906753692021013171376104564654794171951666999009032621460467236692823685991988607159363054170329353334944355625786930020224988415478335601579539769494531176085547834954163494030644162001543873246691321674227292917459616882753537 +9729298153251306194042617127203199623384957034198478276241843041111037695834634873921670474267119187843169195625338744528581029537433535757956376518129793109557221580317097753720451186105453926588775689583539463154010576700049252756460830197065735837134519004638182709904558099057065808050158672835248129 +13582985265193575509847153720290630277475301176695966793104558898916525902171099726111653252346386417687634059875171486934990855171785554727726817192028731914702681172768151028934363876033198780003232825417916826555570603003610443324900765322801514628836373961563717819815659178099324514051673737887522648522145975473923735339139073 +3646154850295010964902624396817474390399390616036693719739415376725561063085178919082942505698777176089060633115597677023110409583667009527018497076154392047301826729011247840192495744913649306569979494349478121435366144715292958165239232610420731738086890347478323006048396719686780691510330825043607290550999833104265740262684222585569281 +1 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046272 +736567904319114813700179347165898017864004333486947405305591758520610240861829766276798698618284354494716156033682943041579601713942220515540203161316988146991665543021307547800992939109024679837929112360581117013918612389794386017956541445146429151471384731055851996508875022310290766702717202280754490927819272344442130311818432332846202054796801431275025655264802408764738515518151514632480908325565788780147963367006809604639382187947539029097971692 +31847793196274107182845849867935019058119806419340392572260824606510195176311496560920629445019152089581060460884957727702584683631406487052881165260753582736592014907778440638252456605285448061563792096352745440411338097615871547824025696771093222358857968371367314896669453345606857912669867603377384655355233299464450205863387455153540545988356938076082061665735266055161074861451503585061555464743511248208302416059151577191074239364588830400998014069 +44462416394276340862910922260389321581298853470913371563358965890746390942505208917810214508921403677924050484037361854923909199530783769557857398908416797467991642660044081596444758567725905941578862500220928052627591160031402858547990440510112144073496748573294083122100295594485512238065152913601534980743295758670057701269862152855527112109603873427804287879276629501582896265202691196110634325565999430887153483257613158570830305101308846059434951620873330091758706311542341633 +11935289041890653422458560211344367565999989567726224393815132782921219808519438180124970259072038417888105302535754774032670805811336900569676094726678661851388189281957447472598923409448779291182901295823514011338832830575108282476521982723289897702706625317681157972521881629518687524749107700488703863037130875637878556278141428758998783243913325146240393321801800775493463196094645471464263521615496507631433158100292031999009575957202146963989209941350094442798986370318517904347234306 +21 +21 +21 +21 +21 +21 +21 +22 +42 +929 +1267650597867046177654064545813 +340282366920938463463374607431768211476 +21 +42 +462 +19089 +26620662555207969730735355461653 +7145929705339707732730866756067132440576 +21 +929 +19089 +824485 +1151026742863277929309890607579157 +308976389164212124824744143548045536001161 +21 +1267650597867046177654064545813 +26620662555207969730735355461653 +1151026742863277929309890607579157 +1606938038272679619211255036084048932956190504430095264907285 +431359145870941220571487096504865044588697904564591140391738786447381 +21 +340282366920938463463374607431768211476 +7145929705339707732730866756067132440576 +308976389164212124824744143548045536001161 +431359145870941220571487096504865044588697904564591140391738786447381 +115792089237316195423570985008687907852589419931798687112530834793049593217046 +21 +57896044618658097611351864738157061705262361561497619362091104892532012613653 +1215816936991820049838389159501298295810509592791450006603913202743172264886293 +52569608513741552631107493182246612028378224297839838380778723242419067453177877 +73391955574979118963811141843059488536193514605218060347731553038824318137413435829926783487818828867436565 +19701003098197239571963727475337245584161626291901231402719522479678259504890677218990119895590117915143388591554581 +21 +115792089237105570840234253759177109864155645142784332660520492325483608801301 +2431633873979216987644919328942719307147268547998470985870930338835155784826901 +105139217027291858322932702413332815756653325789648174055752607031539116791562261 +146783911149691239803259475393272332038744581223672095908357420057841712239442615794649035123910216788213781 +39402006196322807380529480735708200350692396090822410401547663254352517428719749608020233606624972587007562114662421 +21 +231583736816786089484927226016147767929578972263620494977377884571370600267796 +4863258473152507879183471746339103126521158417536030394524935575998782605623296 +210278033029641769252313921222662173280057706815367409439459119190804505043139721 +293567262432083559770702660509494961636846893913475830448684457955877331972488384611363806317219648949452821 +78803862104411649792976274791681038936454943300723566886694079153850261012036590002656572187311458765011955822362646 +21 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049813 +68741202765818979270276983633379582196549482966904360579127216519201261330098607324506894304856394094406282403777947234369674236221393804088784959045653 +2972238671969696817971976244719460030212710977807102828849881552354035489891882640507250477562362182748614496315732194705126866975667884481553178229211157 +4149515561151917970063980879655710938513649460124350952720371065270297197065154634382680097543307069927884450339928718724097725668943949230978441358030208342019760039438410280075285 +1113877103911668754551067286547922686738237475419584309931192581897577662915063323503306740447008536028968181678028580322422866333819711284625174374608617279642589745120484326564854874767381 +21 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348308 +105586487448313957217630953653425358968668408786294503634300774628861320362441676458635398984170320306132770645519405205878947411928992353796866863213314048 +4565358600146146340648043138919534568740519770378829014283100160143146613766525820211473441791745277998502654577696186997051630953882145583216910085604244617 +6373655901930312136397229380018411440828683949391920950832693445711366448193584697763678864931677968612065262908033170282412527802037703004824976134384286640214222530054133889372258325 +1710915231608582551713494414139930175751260546116444122900349352360496966554854730076753484481830650675467827629295222707109502155201699203484369755223655341193278275893163301956243837193027606 +21 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780180 +281563966528794539091054524955215094900633929296509267540226436097922037480312534843090816414714560916129249828990251803876343269504358060681650578506383360 +12174289600387878166413214698063586008084552752439543567929790665567295715815418173215545776407658157706921849748721363710462842319521767576139939299228384393 +16996415738478256005382065682640742151192912704409604594012987116129634408058546371285779101609491343355313613863898166638327059654603396304113335697353121717251389843622698066460540949 +4562440617622195218641171605585119131739514871918667547682857357314343535508689562160604455918497575074715174882382908134196095677901105600185199282794955018371204524886410100925712980030521366 +21 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103253 +563127933057589078182109049910430189801267858593018911357569558066951448610928205184820357265838911550428123265590126067657221108914838323326397307129167893 +24348579200775756332826429396127172016169105504879103405365388510704376920891562395610327828446749127989939805959801641401559846042603485599065178803489734677 +33992831476956512010764131365281484302385825408819231901736066162392911122587750794642859557837487570646738733764326406607430768230396539092082721200286809873288301231428402460695199765 +9124881235244390437282343211170238263479029743837341192530852050551013988199468564099149809149237792502394782872367659707645708326849200364829008985690446628655225628506036591091211274089922581 +21 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369237 +225016807509116112417285197875844925210445041539832647358016193682083470938906753692021013171376104564654794171951666999009032621460467236692823685991988607159363054170329353334944355625786930020224988415478335601579539769494531176085547834954163494030644162001543873246691321674227292917459616882753557 +9729298153251306194042617127203199623384957034198478276241843041111037695834634873921670474267119187843169195625338744528581029537433535757956376518129793109557221580317097753720451186105453926588775689583539463154010576700049252756460830197065735837134519004638182709904558099057065808050158672835248149 +13582985265193575509847153720290630277475301176695966793104558898916525902171099726111653252346386417687634059875171486934990855171785554727726817192028731914702681172768151028934363876033198780003232825417916826555570603003610443324900765322801514628836373961563717819815659178099324514051673737887522648522145975473923735339139093 +3646154850295010964902624396817474390399390616036693719739415376725561063085178919082942505698777176089060633115597677023110409583667009527018497076154392047301826729011247840192495744913649306569979494349478121435366144715292958165239232610420731738086890347478323006048396719686780691510330825043607290550999833104265740262684222585569301 +21 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046292 +736567904319114813700179347165898017864004333486947405305591758520610240861829766276798698618284354494716156033682943041579601713942220515540203161316988146991665543021307547800992939109024679837929112360581117013918612389794386017956541445146429151471384731055851996508875022310290766702717202280754490927819272344442130311818432332846202054796801431275025655264802408764738515518151514632480908325565788780147963367006809604639382187947539029097971712 +31847793196274107182845849867935019058119806419340392572260824606510195176311496560920629445019152089581060460884957727702584683631406487052881165260753582736592014907778440638252456605285448061563792096352745440411338097615871547824025696771093222358857968371367314896669453345606857912669867603377384655355233299464450205863387455153540545988356938076082061665735266055161074861451503585061555464743511248208302416059151577191074239364588830400998014089 +44462416394276340862910922260389321581298853470913371563358965890746390942505208917810214508921403677924050484037361854923909199530783769557857398908416797467991642660044081596444758567725905941578862500220928052627591160031402858547990440510112144073496748573294083122100295594485512238065152913601534980743295758670057701269862152855527112109603873427804287879276629501582896265202691196110634325565999430887153483257613158570830305101308846059434951620873330091758706311542341653 +11935289041890653422458560211344367565999989567726224393815132782921219808519438180124970259072038417888105302535754774032670805811336900569676094726678661851388189281957447472598923409448779291182901295823514011338832830575108282476521982723289897702706625317681157972521881629518687524749107700488703863037130875637878556278141428758998783243913325146240393321801800775493463196094645471464263521615496507631433158100292031999009575957202146963989209941350094442798986370318517904347234326 +908 +908 +908 +908 +908 +908 +908 +909 +929 +1816 +1267650597867046177654064546700 +340282366920938463463374607431768212363 +908 +929 +1349 +19976 +26620662555207969730735355462540 +7145929705339707732730866756067132441463 +908 +1816 +19976 +825372 +1151026742863277929309890607580044 +308976389164212124824744143548045536002048 +908 +1267650597867046177654064546700 +26620662555207969730735355462540 +1151026742863277929309890607580044 +1606938038272679619211255036084048932956190504430095264908172 +431359145870941220571487096504865044588697904564591140391738786448268 +908 +340282366920938463463374607431768212363 +7145929705339707732730866756067132441463 +308976389164212124824744143548045536002048 +431359145870941220571487096504865044588697904564591140391738786448268 +115792089237316195423570985008687907852589419931798687112530834793049593217933 +908 +57896044618658097611351864738157061705262361561497619362091104892532012614540 +1215816936991820049838389159501298295810509592791450006603913202743172264887180 +52569608513741552631107493182246612028378224297839838380778723242419067453178764 +73391955574979118963811141843059488536193514605218060347731553038824318137413435829926783487818828867437452 +19701003098197239571963727475337245584161626291901231402719522479678259504890677218990119895590117915143388591555468 +908 +115792089237105570840234253759177109864155645142784332660520492325483608802188 +2431633873979216987644919328942719307147268547998470985870930338835155784827788 +105139217027291858322932702413332815756653325789648174055752607031539116791563148 +146783911149691239803259475393272332038744581223672095908357420057841712239442615794649035123910216788214668 +39402006196322807380529480735708200350692396090822410401547663254352517428719749608020233606624972587007562114663308 +908 +231583736816786089484927226016147767929578972263620494977377884571370600268683 +4863258473152507879183471746339103126521158417536030394524935575998782605624183 +210278033029641769252313921222662173280057706815367409439459119190804505043140608 +293567262432083559770702660509494961636846893913475830448684457955877331972488384611363806317219648949453708 +78803862104411649792976274791681038936454943300723566886694079153850261012036590002656572187311458765011955822363533 +908 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998050700 +68741202765818979270276983633379582196549482966904360579127216519201261330098607324506894304856394094406282403777947234369674236221393804088784959046540 +2972238671969696817971976244719460030212710977807102828849881552354035489891882640507250477562362182748614496315732194705126866975667884481553178229212044 +4149515561151917970063980879655710938513649460124350952720371065270297197065154634382680097543307069927884450339928718724097725668943949230978441358030208342019760039438410280076172 +1113877103911668754551067286547922686738237475419584309931192581897577662915063323503306740447008536028968181678028580322422866333819711284625174374608617279642589745120484326564854874768268 +908 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486349195 +105586487448313957217630953653425358968668408786294503634300774628861320362441676458635398984170320306132770645519405205878947411928992353796866863213314935 +4565358600146146340648043138919534568740519770378829014283100160143146613766525820211473441791745277998502654577696186997051630953882145583216910085604245504 +6373655901930312136397229380018411440828683949391920950832693445711366448193584697763678864931677968612065262908033170282412527802037703004824976134384286640214222530054133889372259212 +1710915231608582551713494414139930175751260546116444122900349352360496966554854730076753484481830650675467827629295222707109502155201699203484369755223655341193278275893163301956243837193028493 +908 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690781067 +281563966528794539091054524955215094900633929296509267540226436097922037480312534843090816414714560916129249828990251803876343269504358060681650578506384247 +12174289600387878166413214698063586008084552752439543567929790665567295715815418173215545776407658157706921849748721363710462842319521767576139939299228385280 +16996415738478256005382065682640742151192912704409604594012987116129634408058546371285779101609491343355313613863898166638327059654603396304113335697353121717251389843622698066460541836 +4562440617622195218641171605585119131739514871918667547682857357314343535508689562160604455918497575074715174882382908134196095677901105600185199282794955018371204524886410100925712980030522253 +908 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387104140 +563127933057589078182109049910430189801267858593018911357569558066951448610928205184820357265838911550428123265590126067657221108914838323326397307129168780 +24348579200775756332826429396127172016169105504879103405365388510704376920891562395610327828446749127989939805959801641401559846042603485599065178803489735564 +33992831476956512010764131365281484302385825408819231901736066162392911122587750794642859557837487570646738733764326406607430768230396539092082721200286809873288301231428402460695200652 +9124881235244390437282343211170238263479029743837341192530852050551013988199468564099149809149237792502394782872367659707645708326849200364829008985690446628655225628506036591091211274089923468 +908 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375370124 +225016807509116112417285197875844925210445041539832647358016193682083470938906753692021013171376104564654794171951666999009032621460467236692823685991988607159363054170329353334944355625786930020224988415478335601579539769494531176085547834954163494030644162001543873246691321674227292917459616882754444 +9729298153251306194042617127203199623384957034198478276241843041111037695834634873921670474267119187843169195625338744528581029537433535757956376518129793109557221580317097753720451186105453926588775689583539463154010576700049252756460830197065735837134519004638182709904558099057065808050158672835249036 +13582985265193575509847153720290630277475301176695966793104558898916525902171099726111653252346386417687634059875171486934990855171785554727726817192028731914702681172768151028934363876033198780003232825417916826555570603003610443324900765322801514628836373961563717819815659178099324514051673737887522648522145975473923735339139980 +3646154850295010964902624396817474390399390616036693719739415376725561063085178919082942505698777176089060633115597677023110409583667009527018497076154392047301826729011247840192495744913649306569979494349478121435366144715292958165239232610420731738086890347478323006048396719686780691510330825043607290550999833104265740262684222585570188 +908 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957047179 +736567904319114813700179347165898017864004333486947405305591758520610240861829766276798698618284354494716156033682943041579601713942220515540203161316988146991665543021307547800992939109024679837929112360581117013918612389794386017956541445146429151471384731055851996508875022310290766702717202280754490927819272344442130311818432332846202054796801431275025655264802408764738515518151514632480908325565788780147963367006809604639382187947539029097972599 +31847793196274107182845849867935019058119806419340392572260824606510195176311496560920629445019152089581060460884957727702584683631406487052881165260753582736592014907778440638252456605285448061563792096352745440411338097615871547824025696771093222358857968371367314896669453345606857912669867603377384655355233299464450205863387455153540545988356938076082061665735266055161074861451503585061555464743511248208302416059151577191074239364588830400998014976 +44462416394276340862910922260389321581298853470913371563358965890746390942505208917810214508921403677924050484037361854923909199530783769557857398908416797467991642660044081596444758567725905941578862500220928052627591160031402858547990440510112144073496748573294083122100295594485512238065152913601534980743295758670057701269862152855527112109603873427804287879276629501582896265202691196110634325565999430887153483257613158570830305101308846059434951620873330091758706311542342540 +11935289041890653422458560211344367565999989567726224393815132782921219808519438180124970259072038417888105302535754774032670805811336900569676094726678661851388189281957447472598923409448779291182901295823514011338832830575108282476521982723289897702706625317681157972521881629518687524749107700488703863037130875637878556278141428758998783243913325146240393321801800775493463196094645471464263521615496507631433158100292031999009575957202146963989209941350094442798986370318517904347235213 +1267650597867046177654064545792 +1267650597867046177654064545792 +1267650597867046177654064545792 +1267650597867046177654064545792 +1267650597867046177654064545792 +1267650597867046177654064545792 +1267650597867046177654064545792 +1267650597867046177654064545793 +1267650597867046177654064545813 +1267650597867046177654064546700 +2535301195734092355308129091584 +340282368188589061330420785085832757247 +1267650597867046177654064545792 +1267650597867046177654064545813 +1267650597867046177654064546233 +1267650597867046177654064564860 +27888313153075015908389420007424 +7145929706607358330597912933721196986347 +1267650597867046177654064545792 +1267650597867046177654064546700 +1267650597867046177654064564860 +1267650597867046177654065370256 +1152294393461144975487544672124928 +308976389165479775422611189725699600546932 +1267650597867046177654064545792 +2535301195734092355308129091584 +27888313153075015908389420007424 +1152294393461144975487544672124928 +1606938038272679619211255036085316583554057550607749329453056 +431359145870941220571487096504865044589965555162458186569392850993152 +1267650597867046177654064545792 +340282368188589061330420785085832757247 +7145929706607358330597912933721196986347 +308976389165479775422611189725699600546932 +431359145870941220571487096504865044589965555162458186569392850993152 +115792089237316195423570985008687907852589419933066337710397880970703657762817 +1267650597867046177654064545792 +57896044618658097611351864738157061705262361562765269959958151070186077159424 +1215816936991820049838389159501298295810509592792717657201780248920826329432064 +52569608513741552631107493182246612028378224297841106031376590288596721517723648 +73391955574979118963811141843059488536193514605218060347731553038824318137414703480524650533996482931982336 +19701003098197239571963727475337245584161626291901231402719522479678259504890677218991387546187984961321042656100352 +1267650597867046177654064545792 +115792089237105570840234253759177109864155645144051983258387538503137673347072 +2431633873979216987644919328942719307147268547999738636468797385012809849372672 +105139217027291858322932702413332815756653325789649441706350474077716770856108032 +146783911149691239803259475393272332038744581223672095908357420057841712239443883445246902170087870852759552 +39402006196322807380529480735708200350692396090822410401547663254352517428719749608021501257222839633185216179208192 +1267650597867046177654064545792 +231583736816786089484927226016147767929578972264888145575244930749024664813567 +4863258473152507879183471746339103126521158417537298045122802622176436670169067 +210278033029641769252313921222662173280057706815368677090056986236982159107685492 +293567262432083559770702660509494961636846893913475830448684457955877331972489652261961673363397303013998592 +78803862104411649792976274791681038936454943300723566886694079153850261012036590002657839837909325811189609886908417 +1267650597867046177654064545792 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725447442614227457227324739062595584 +68741202765818979270276983633379582196549482966904360579127216519201261330098607324506894304856394094406282403777947234370941886819260850266439023591424 +2972238671969696817971976244719460030212710977807102828849881552354035489891882640507250477562362182748614496315732194705128134626265751527730832293756928 +4149515561151917970063980879655710938513649460124350952720371065270297197065154634382680097543307069927884450339928718724097725668943949230978441358031475992617627085616064344621056 +1113877103911668754551067286547922686738237475419584309931192581897577662915063323503306740447008536028968181678028580322422866333819711284625174374608617279643857395718351372742508939313152 +1267650597867046177654064545792 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851379715837692741036504647550894079 +105586487448313957217630953653425358968668408786294503634300774628861320362441676458635398984170320306132770645519405205878948679579590220843044517277859819 +4565358600146146340648043138919534568740519770378829014283100160143146613766525820211473441791745277998502654577696186997051632221532743450263087739668790388 +6373655901930312136397229380018411440828683949391920950832693445711366448193584697763678864931677968612065262908033170282412527802037703004824976134384287907864820397100311543436804096 +1710915231608582551713494414139930175751260546116444122900349352360496966554854730076753484481830650675467827629295222707109502155201699203484369755223655341193279543543761169002421491257573377 +1267650597867046177654064545792 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756017613817472060411970538755325951 +281563966528794539091054524955215094900633929296509267540226436097922037480312534843090816414714560916129249828990251803876344537154955927727828232570929131 +12174289600387878166413214698063586008084552752439543567929790665567295715815418173215545776407658157706921849748721363710462843587172365443186116953292930164 +16996415738478256005382065682640742151192912704409604594012987116129634408058546371285779101609491343355313613863898166638327059654603396304113335697353122984901987710668875720525086720 +4562440617622195218641171605585119131739514871918667547682857357314343535508689562160604455918497575074715174882382908134196095677901105600185199282794955018371205792537007967971890634095067137 +1267650597867046177654064545792 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459868939503685406252196573451649024 +563127933057589078182109049910430189801267858593018911357569558066951448610928205184820357265838911550428123265590126067657222376565436190372574961193713664 +24348579200775756332826429396127172016169105504879103405365388510704376920891562395610327828446749127989939805959801641401559847310254083466111356457554280448 +33992831476956512010764131365281484302385825408819231901736066162392911122587750794642859557837487570646738733764326406607430768230396539092082721200286811140938899098474580114759745536 +9124881235244390437282343211170238263479029743837341192530852050551013988199468564099149809149237792502394782872367659707645708326849200364829008985690446628655226896156634458137388928154468352 +1267650597867046177654064545792 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059367521063656309566056683439915008 +225016807509116112417285197875844925210445041539832647358016193682083470938906753692021013171376104564654794171951666999009032621460467236692823685991988607159363054170329353334944355625786930020224988415478335601579539769494531176085547834954163494030644162001543873246692589324825159963637270947299328 +9729298153251306194042617127203199623384957034198478276241843041111037695834634873921670474267119187843169195625338744528581029537433535757956376518129793109557221580317097753720451186105453926588775689583539463154010576700049252756460830197065735837134519004638182709904559366707663675096336326899793920 +13582985265193575509847153720290630277475301176695966793104558898916525902171099726111653252346386417687634059875171486934990855171785554727726817192028731914702681172768151028934363876033198780003232825417916826555570603003610443324900765322801514628836373961563717819815659178099324514051673737887523916172743842520101389403684864 +3646154850295010964902624396817474390399390616036693719739415376725561063085178919082942505698777176089060633115597677023110409583667009527018497076154392047301826729011247840192495744913649306569979494349478121435366144715292958165239232610420731738086890347478323006048396719686780691510330825043607290551001100754863607308861876650115072 +1267650597867046177654064545792 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571754105966758923615108084021592063 +736567904319114813700179347165898017864004333486947405305591758520610240861829766276798698618284354494716156033682943041579601713942220515540203161316988146991665543021307547800992939109024679837929112360581117013918612389794386017956541445146429151471384731055851996508875022310290766702717202280754490927819272344442130311818432332846202054796801431275025655264802408764738515518151514632480908325565788780147963367006810872289980054993716683162517483 +31847793196274107182845849867935019058119806419340392572260824606510195176311496560920629445019152089581060460884957727702584683631406487052881165260753582736592014907778440638252456605285448061563792096352745440411338097615871547824025696771093222358857968371367314896669453345606857912669867603377384655355233299464450205863387455153540545988356938076082061665735266055161074861451503585061555464743511248208302416059151578458724837231635008055062559860 +44462416394276340862910922260389321581298853470913371563358965890746390942505208917810214508921403677924050484037361854923909199530783769557857398908416797467991642660044081596444758567725905941578862500220928052627591160031402858547990440510112144073496748573294083122100295594485512238065152913601534980743295758670057701269862152855527112109603873427804287879276629501582896265202691196110634325565999430887153483257613158570830305101308846059434952888523927958804883965606887424 +11935289041890653422458560211344367565999989567726224393815132782921219808519438180124970259072038417888105302535754774032670805811336900569676094726678661851388189281957447472598923409448779291182901295823514011338832830575108282476521982723289897702706625317681157972521881629518687524749107700488703863037130875637878556278141428758998783243913325146240393321801800775493463196094645471464263521615496507631433158100292031999009575957202146963989209941350095710449584237364695558411780097 +340282366920938463463374607431768211455 +340282366920938463463374607431768211455 +340282366920938463463374607431768211455 +340282366920938463463374607431768211455 +340282366920938463463374607431768211455 +340282366920938463463374607431768211455 +340282366920938463463374607431768211455 +340282366920938463463374607431768211456 +340282366920938463463374607431768211476 +340282366920938463463374607431768212363 +340282368188589061330420785085832757247 +680564733841876926926749214863536422910 +340282366920938463463374607431768211455 +340282366920938463463374607431768211476 +340282366920938463463374607431768211896 +340282366920938463463374607431768230523 +340282393541601018671344338167123673087 +7486212072260646196194241363498900652010 +340282366920938463463374607431768211455 +340282366920938463463374607431768212363 +340282366920938463463374607431768230523 +340282366920938463463374607431769035919 +340283517947681326741303917322375790591 +309316671531133063288207518155477304212595 +340282366920938463463374607431768211455 +340282368188589061330420785085832757247 +340282393541601018671344338167123673087 +340283517947681326741303917322375790591 +1606938038272679619211595318450969871419653879037527033118719 +431359145870941220571487096505205326955618843028054514999170554658815 +340282366920938463463374607431768211455 +680564733841876926926749214863536422910 +7486212072260646196194241363498900652010 +309316671531133063288207518155477304212595 +431359145870941220571487096505205326955618843028054514999170554658815 +115792089237316195423570985008687907852929702298719625575994209400481361428480 +340282366920938463463374607431768211455 +57896044618658097611351864738157061705602643928418557825554479499963780825087 +1215816936991820049838389159501298295810849875158370945067376577350604033097727 +52569608513741552631107493182246612028378564580206759319242186617026499221389311 +73391955574979118963811141843059488536193514605218060347731553038824658419780356768390246862426260635647999 +19701003098197239571963727475337245584161626291901231402719522479678259504891017501357040834053581289750820359766015 +340282366920938463463374607431768211455 +115792089237105570840234253759177109864495927509705271123983866932915377012735 +2431633873979216987644919328942719307147608830365391924334393713442587553038335 +105139217027291858322932702413332815756653666072015094994216070406146548559773695 +146783911149691239803259475393272332038744581223672095908357420057842052521809536733112498498517648556425215 +39402006196322807380529480735708200350692396090822410401547663254352517428720089890387154545088435961614993882873855 +340282366920938463463374607431768211455 +231583736816786089484927226016147767929919254630541433440841259178802368479230 +4863258473152507879183471746339103126521498699902951332988398950606214373834730 +210278033029641769252313921222662173280058047097734330377922582565411936811351155 +293567262432083559770702660509494961636846893913475830448684457955877672254855305549827269691827080717664255 +78803862104411649792976274791681038936454943300723566886694079153850261012036930285023493125774922139619387590574080 +340282366920938463463374607431768211455 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656433007813095902093053555754516766261247 +68741202765818979270276983633379582196549482966904360579127216519201261330098607324506894304856394094406282403778287516736595174684857178696216727257087 +2972238671969696817971976244719460030212710977807102828849881552354035489891882640507250477562362182748614496315732534987493787914131347856160609997422591 +4149515561151917970063980879655710938513649460124350952720371065270297197065154634382680097543307069927884450339928718724097725668943949230978781640397129280483223414045842048286719 +1113877103911668754551067286547922686738237475419584309931192581897577662915063323503306740447008536028968181678028580322422866333819711284625174374608957562009510683583947701172286642978815 +340282366920938463463374607431768211455 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352969133745369125558337364934425254559742 +105586487448313957217630953653425358968668408786294503634300774628861320362441676458635398984170320306132770645519405546161314332867455817171474294981525482 +4565358600146146340648043138919534568740519770378829014283100160143146613766525820211473441791745277998502654577696187337333997874820609046591517517372456051 +6373655901930312136397229380018411440828683949391920950832693445711366448193584697763678864931677968612065262908033170282412527802037703004824976474666653561152685993428741321140469759 +1710915231608582551713494414139930175751260546116444122900349352360496966554854730076753484481830650675467827629295222707109502155201699203484369755223655681475645196831626765330851268961239040 +340282366920938463463374607431768211455 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107569038383267105337656740400316458991614 +281563966528794539091054524955215094900633929296509267540226436097922037480312534843090816414714560916129249828990252144158710190442821524056258010274594794 +12174289600387878166413214698063586008084552752439543567929790665567295715815418173215545776407658157706921849748721364050745209240460231039514546730996595827 +16996415738478256005382065682640742151192912704409604594012987116129634408058546371285779101609491343355313613863898166638327059654603396304113336037635488638189853306997305498228752383 +4562440617622195218641171605585119131739514871918667547682857357314343535508689562160604455918497575074715174882382908134196095677901105600185199282794955358653571445824873564300320411798732800 +340282366920938463463374607431768211455 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244438742234592791551002580626351155314687 +563127933057589078182109049910430189801267858593018911357569558066951448610928205184820357265838911550428123265590126407939588029853301786701004738897379327 +24348579200775756332826429396127172016169105504879103405365388510704376920891562395610327828446749127989939805959801641741842212963541949062439786235257946111 +33992831476956512010764131365281484302385825408819231901736066162392911122587750794642859557837487570646738733764326406607430768230396539092082721540569176794226764694803009892463411199 +9124881235244390437282343211170238263479029743837341192530852050551013988199468564099149809149237792502394782872367659707645708326849200364829008985690446968937592549444500054465818705858134015 +340282366920938463463374607431768211455 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359572341733174351521905894486461143580671 +225016807509116112417285197875844925210445041539832647358016193682083470938906753692021013171376104564654794171951666999009032621460467236692823685991988607159363054170329353334944355625786930020224988415478335601579539769494531176085547834954163494030644162001544213529058242612690756292067048650964991 +9729298153251306194042617127203199623384957034198478276241843041111037695834634873921670474267119187843169195625338744528581029537433535757956376518129793109557221580317097753720451186105453926588775689583539463154010576700049252756460830197065735837134519004638183050186925019995529271424766104603459583 +13582985265193575509847153720290630277475301176695966793104558898916525902171099726111653252346386417687634059875171486934990855171785554727726817192028731914702681172768151028934363876033198780003232825417916826555570603003610443324900765322801514628836373961563717819815659178099324514051674078169889569460609438848531167107350527 +3646154850295010964902624396817474390399390616036693719739415376725561063085178919082942505698777176089060633115597677023110409583667009527018497076154392047301826729011247840192495744913649306569979494349478121435366144715292958165239232610420731738086890347478323006048396719686780691510330825043607630833366754042729203637291654353780735 +340282366920938463463374607431768211455 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998595854119759254624519943537861725257726 +736567904319114813700179347165898017864004333486947405305591758520610240861829766276798698618284354494716156033682943041579601713942220515540203161316988146991665543021307547800992939109024679837929112360581117013918612389794386017956541445146429151471384731055851996508875022310290766702717202280754490927819272344442130311818432332846202054796801431275025655264802408764738515518151514632480908325565788780147963707289176525577845651322146460866183146 +31847793196274107182845849867935019058119806419340392572260824606510195176311496560920629445019152089581060460884957727702584683631406487052881165260753582736592014907778440638252456605285448061563792096352745440411338097615871547824025696771093222358857968371367314896669453345606857912669867603377384655355233299464450205863387455153540545988356938076082061665735266055161074861451503585061555464743511248208302416399433944112012702827963437832766225523 +44462416394276340862910922260389321581298853470913371563358965890746390942505208917810214508921403677924050484037361854923909199530783769557857398908416797467991642660044081596444758567725905941578862500220928052627591160031402858547990440510112144073496748573294083122100295594485512238065152913601534980743295758670057701269862152855527112109603873427804287879276629501582896265202691196110634325565999430887153483257613158570830305101308846399717318541811793555133313743310553087 +11935289041890653422458560211344367565999989567726224393815132782921219808519438180124970259072038417888105302535754774032670805811336900569676094726678661851388189281957447472598923409448779291182901295823514011338832830575108282476521982723289897702706625317681157972521881629518687524749107700488703863037130875637878556278141428758998783243913325146240393321801800775493463196094645471464263521615496507631433158100292031999009575957202146963989210281632461363737449833693125336115445760 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +57896044618658097611351864738157061705262361561497619362091104892532012613633 +57896044618658097611351864738157061705262361561497619362091104892532012613653 +57896044618658097611351864738157061705262361561497619362091104892532012614540 +57896044618658097611351864738157061705262361562765269959958151070186077159424 +57896044618658097611351864738157061705602643928418557825554479499963780825087 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +57896044618658097611351864738157061705262361561497619362091104892532012613653 +57896044618658097611351864738157061705262361561497619362091104892532012614073 +57896044618658097611351864738157061705262361561497619362091104892532012632700 +57896044618658097611351864738157061705262361588118281917299074623267368075264 +57896044618658097611351864738157061712408291266837327094821971648599145054187 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +57896044618658097611351864738157061705262361561497619362091104892532012614540 +57896044618658097611351864738157061705262361561497619362091104892532012632700 +57896044618658097611351864738157061705262361561497619362091104892532013438096 +57896044618658097611351864738157061705262362712524362225369034202422620192768 +57896044618658097611351864738157062014238750725709744186835248440577548614772 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +57896044618658097611351864738157061705262361562765269959958151070186077159424 +57896044618658097611351864738157061705262361588118281917299074623267368075264 +57896044618658097611351864738157061705262362712524362225369034202422620192768 +57896044618658099218289903010836680916517397645546552318281609322627277520896 +57896045050017243482293085309644158210127406150195523926682245284270799060992 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +57896044618658097611351864738157061705602643928418557825554479499963780825087 +57896044618658097611351864738157061712408291266837327094821971648599145054187 +57896044618658097611351864738157062014238750725709744186835248440577548614772 +57896045050017243482293085309644158210127406150195523926682245284270799060992 +173688133855974293034922849746844969557851781493296306474621939685581605830657 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +115792089237316195222703729476314123410524723122995238724182209785064025227264 +1273712981610478147449741024239455357515771954352947625966004307635704277499904 +52627504558360210728718845046984769090083486659401336000140814347311599465791488 +73391955574979118963811141843117384580812172702829412212469710100529580498974933449288874592711360880050176 +19701003098197239571963727475337245584219522336519889500330874344416416566595939580551617514952209020035920604168192 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +173688133855763668451586118497334171569418006704281952022611597218015621414912 +2489529918597875085256271193680876368852530909559968605233021443727687797440512 +105197113071910516420544054278070972818358588151209671675114698136431648804175872 +146783911149691239803259475393330228083363239321283447773095577119546974601004113414011126228802748800827392 +39402006196322807380529480735708200350750292135441068499159015119090674490425011969581731225987063691900094127276032 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +289479781435444187096279090754304829634841333825118114339468989463902612881407 +4921154517771165976794823611077260188226420779097528013887026680891314618236907 +210335929074260427349925273087400330341762969176928907058821210295697037055753332 +293567262432083559770702660509552857681465552011087182313422615017582594334049882230725897422112180962066432 +78803862104411649792976274791681038936512839345342224984305431018588418073741852364218069806673549869904487834976257 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +3273390607896141870013189696827599152216642046043064789482248405676250539586401155309462588318799202567027652361355087007672582991681286039617010663424 +68741202765818979270276983633379582196549482966904360579127216519201261330156503369125552402467745959144439465483209595931171855583484908981316971659264 +2972238671969696817971976244719460030212710977807102828849881552354035489891940536551869135659973534613352653377437457066688364595029975586445710241824768 +4149515561151917970063980879655710938513649460124350952720371065270297197065154634382680097543307069927942346384547376821709077533682106292683703719591705961381851144330942292688896 +1113877103911668754551067286547922686738237475419584309931192581897577662915063323503306740447008536028968181678086476367041524431431063149363331436313879641204087364482575431457386887380992 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +5027927973729236057982426364448826617555638513633071601633370220421967636306804394074875752581912318823441521134057891212939945806456965095219525498961919 +105586487448313957217630953653425358968668408786294503634300774628861320362441734354680017642267931657997508802581110468240508909548354444901759395225927659 +4565358600146146340648043138919534568740519770378829014283100160143146613766525878107518060449842889350367392734757892259413192451501507674321802617616858228 +6373655901930312136397229380018411440828683949391920950832693445711366448193584697763678864931677968612065320804077788940510139153902441161886681396745848137833584621159026421384871936 +1710915231608582551713494414139930175751260546116444122900349352360496966554854730076753484481830650675467827629295280603154120813299310555349107912285360603554839773512525393061136369205641217 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +13407807929942597099574024997867385471458758537929012740010782671329620832395892888572752773084019014537559577489812491117577843786236284470685416703393791 +281563966528794539091054524955215094900633929296509267540226436097922037480312592739135435072812172267993987986051957066237904767123720151786543110518996971 +12174289600387878166413214698063586008084552752439543567929790665567295715815418231111590395065755769058786587905783068972824403817141129667244831831240998004 +16996415738478256005382065682640742151192912704409604594012987116129634408058546371285779101609491343355313671759942785296424671006468134461175040959714683214870751934727590598473154560 +4562440617622195218641171605585119131739514871918667547682857357314343535508689562160604455918497575074715174882382966030240714335998716952049937439856660280732766022505772192030605512043134977 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +26815615859885194199148049995734770942917517075858043397979502765092926124329972428655111861232797616170839264946949360821429169472449630310911451399716864 +563127933057589078182109049910430189801267858593018911357569558066951448610928263080864975923936522902292861422651831330018782606534200414431289839141781504 +24348579200775756332826429396127172016169105504879103405365388510704376920891562453506372447104846739341804544116863346663921407540222847690170071335502348288 +33992831476956512010764131365281484302385825408819231901736066162392911122587750794642859557837487570646738791660371025265528379582261277249144426462648371370907663322533294992707813376 +9124881235244390437282343211170238263479029743837341192530852050551013988199468564099149809149237792502394782872367717603690326984946811716693747142752151891016787126125398682196103806102536192 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356940333001073316904952470628102164776064494420927751032420533624771561387982848 +225016807509116112417285197875844925210445041539832647358016193682083470938906753692021013171376104564654794171951666999009032621460467236692823685991988607159363054170329353334944355625786930020224988415478335601579539769494589072130166493051774845895382319063249135608252819293589384022352148895367168 +9729298153251306194042617127203199623384957034198478276241843041111037695834634873921670474267119187843169195625338744528581029537433535757956376518129793109557221580317097753720451186105453926588775689583539463154010576700049310652505448855163347188999257161699887972266119596676427899155051204847861760 +13582985265193575509847153720290630277475301176695966793104558898916525902171099726111653252346386417687634059875171486934990855171785554727726817192028731914702681172768151028934363876033198780003232825417916826555570603003610443324900765322801514628836431857608336477913270529964062671113379000249084146141508066578816267351752704 +3646154850295010964902624396817474390399390616036693719739415376725561063085178919082942505698777176089060633115597677023110409583667009527018497076154392047301826729011247840192495744913649306569979494349478121435366144715292958165239232610420731738086890347478380902093015377784392043375068982105312552912561330723627831367576754598182912 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463796730242309831072892700701204289449703517933314335935523147673822961969659903 +736567904319114813700179347165898017864004333486947405305591758520610240861829766276798698618284354494716156033682943041579601713942220515540203161316988146991665543021307547800992939109024679837929112360581117013918612389794386017956541445146429151471384731055851996508875022310290766702717202280754490927819272344442130311818432332846202054796801431275025655264802408764738573414196133290578519677430526937209668629368371102258744279052431561110585323 +31847793196274107182845849867935019058119806419340392572260824606510195176311496560920629445019152089581060460884957727702584683631406487052881165260753582736592014907778440638252456605285448061563792096352745440411338097615871547824025696771093222358857968371367314896669453345606857912669867603377384655355233299464450205863387455153540545988356938076082061665735266055161074919347548203719653076095375986365364121321513138688693601455693722933010627700 +44462416394276340862910922260389321581298853470913371563358965890746390942505208917810214508921403677924050484037361854923909199530783769557857398908416797467991642660044081596444758567725905941578862500220928052627591160031402858547990440510112144073496748573294083122100295594485512238065152913601534980743295758670057701269862152855527112109603873427804287879276629501582896265202691196110634325565999488783198101915710769922695043258370551321796513118492692182863598843554955264 +11935289041890653422458560211344367565999989567726224393815132782921219808519438180124970259072038417888105302535754774032670805811336900569676094726678661851388189281957447472598923409448779291182901295823514011338832830575108282476521982723289897702706625317681157972521881629518687524749107700488703863037130875637878556278141428758998783243913325146240393321801800775493463196094645471464263521615496507631433215996336650657107187309066885121050915203711655940418348461423410436359847937 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +115792089237105570840234253759177109864155645142784332660520492325483608801281 +115792089237105570840234253759177109864155645142784332660520492325483608801301 +115792089237105570840234253759177109864155645142784332660520492325483608802188 +115792089237105570840234253759177109864155645144051983258387538503137673347072 +115792089237105570840234253759177109864495927509705271123983866932915377012735 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +115792089237105570840234253759177109864155645142784332660520492325483608801301 +115792089237105570840234253759177109864155645142784332660520492325483608801721 +115792089237105570840234253759177109864155645142784332660520492325483608820348 +115792089237105570840234253759177109864155645169404995215728462056218964262912 +115792089237105570840234253759177109871301574848124040393251359081550741241835 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +115792089237105570840234253759177109864155645142784332660520492325483608802188 +115792089237105570840234253759177109864155645142784332660520492325483608820348 +115792089237105570840234253759177109864155645142784332660520492325483609625744 +115792089237105570840234253759177109864155646293811075523798421635374216380416 +115792089237105570840234253759177110173132034306996457485264635873529144802420 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +115792089237105570840234253759177109864155645144051983258387538503137673347072 +115792089237105570840234253759177109864155645169404995215728462056218964262912 +115792089237105570840234253759177109864155646293811075523798421635374216380416 +115792089237105572447172292031856729075410681226833265616710996755578873708544 +115792089668464716711175474330664206369020689731482237225111632717222395248640 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +115792089237105570840234253759177109864495927509705271123983866932915377012735 +115792089237105570840234253759177109871301574848124040393251359081550741241835 +115792089237105570840234253759177110173132034306996457485264635873529144802420 +115792089668464716711175474330664206369020689731482237225111632717222395248640 +231584178474421766263805238767865017716745065074583019773051327118533202018305 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +173688133855763668451586118497334171569418006704281952022611597218015621414912 +1331609026228925620678623413260475405674665237934234339264433695068655873687552 +52685400602978658201947727436005789138242379942982622713439243734744551061979136 +73391955574979118963811141843175280625430620176058294601490730148688473782556220162587303980144312476237824 +19701003098197239571963727475337245584277418381138336973559756733437436614754832864132904228250638407468872200355840 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +231584178474211141680468507518354219728311290285568665321040984650967217602560 +2547425963216322558485153582701896417011424193141255318531450831160639393628160 +105255009116528963893772936667091992866517481434790958388413127523864600400363520 +146783911149691239803259475393388124127981686794512330162116597167705867884585400127309555616235700397015040 +39402006196322807380529480735708200350808188180059515972387897508111694538583905253163017939285493079333045723463680 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +347375826053891660325161479775324877793734617406404827637898376896854209069055 +4979050562389613450023706000098280236385314062678814727185456068324266214424555 +210393825118878874823154155476421350389921862460510193772119639683129988651940980 +293567262432083559770702660509610753726083999484316064702443635065741487617631168944024326809545132558254080 +78803862104411649792976274791681038936570735389960672457534313407609438121900745647799356519971979257337439431163905 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +3273390607896141870013189696827599152216642046043064789482248405676250539644297199927910061547681591588047700520248370588959296290110673472568606851072 +68741202765818979270276983633379582196549482966904360579127216519201261330214399413743999875696628348165459513642102879512458568881914296414268567846912 +2972238671969696817971976244719460030212710977807102828849881552354035489891998432596487583133202417002373673425596350350269651308328404973878661838012416 +4149515561151917970063980879655710938513649460124350952720371065270297197065154634382680097543307069928000242429165824294937959922703126340842597003172992674680280531763893888876544 +1113877103911668754551067286547922686738237475419584309931192581897577662915063323503306740447008536028968181678144372411659971904659945538384351484472772924785374077781004818890338483568640 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +5027927973729236057982426364448826617555638513633071601633370220421967636306862290119494200055141201212462541182216784496521232519755394482652477095149567 +105586487448313957217630953653425358968668408786294503634300774628861320362441792250724636089741160540386529822629269361524090196261652874289192346822115307 +4565358600146146340648043138919534568740519770378829014283100160143146613766525936003562678897316118232756413754806051152696773738214806103709235569213045876 +6373655901930312136397229380018411440828683949391920950832693445711366448193584697763678864931677968612065378700122407387983368036291462181934840290029429424546883050546459372981059584 +1710915231608582551713494414139930175751260546116444122900349352360496966554854730076753484481830650675467827629295338499198739260772539437738128932333519496838421060225823822448569320801828865 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +13407807929942597099574024997867385471458758537929012740010782671329620832395950784617371220557247896926580597537971384401159130499534713858118368299581439 +281563966528794539091054524955215094900633929296509267540226436097922037480312650635180053520285401150383009006100115959521486053837018581173976062115184619 +12174289600387878166413214698063586008084552752439543567929790665567295715815418289007635013513228997941175608925831227866107985103854428096632264782837185652 +16996415738478256005382065682640742151192912704409604594012987116129634408058546371285779101609491343355313729655987403743897899888857155481223199852998264501584050364115023550069342208 +4562440617622195218641171605585119131739514871918667547682857357314343535508689562160604455918497575074715174882383023926285332783471945834438958459904819174016347309219070621418038463639322625 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +26815615859885194199148049995734770942917517075858043397979502765092926124330030324699730308706026498559860284995108254105010456185748059698344402995904512 +563127933057589078182109049910430189801267858593018911357569558066951448610928320976909594371409751784681882442699990223302363893247498843818722790737969152 +24348579200775756332826429396127172016169105504879103405365388510704376920891562511402417065552319968224193565136911505557204988826936146119557504287098535936 +33992831476956512010764131365281484302385825408819231901736066162392911122587750794642859557837487570646738849556415643713001608464650298269192585355931952657620961751920727944304001024 +9124881235244390437282343211170238263479029743837341192530852050551013988199468564099149809149237792502394782872367775499734945432420040599082768162800310784300368412838697111583536757698723840 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356998229045691764378181353017123184824223387704509037745718963012204512984170496 +225016807509116112417285197875844925210445041539832647358016193682083470938906753692021013171376104564654794171951666999009032621460467236692823685991988607159363054170329353334944355625786930020224988415478335601579539769494646968174784940525003728284403339111408028891834106006887813409785100491554816 +9729298153251306194042617127203199623384957034198478276241843041111037695834634873921670474267119187843169195625338744528581029537433535757956376518129793109557221580317097753720451186105453926588775689583539463154010576700049368548550067302636576071388278181748046865549700883389726328542484156444049408 +13582985265193575509847153720290630277475301176695966793104558898916525902171099726111653252346386417687634059875171486934990855171785554727726817192028731914702681172768151028934363876033198780003232825417916826555570603003610443324900765322801514628836489753652954925386499412353083691161537893532665432854806495966249218947940352 +3646154850295010964902624396817474390399390616036693719739415376725561063085178919082942505698777176089060633115597677023110409583667009527018497076154392047301826729011247840192495744913649306569979494349478121435366144715292958165239232610420731738086890347478438798137633825257620925764090002153471446196142617436926260755009706194370560 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463854626286928278546121583090225309497862411216895622648821577061255913565847551 +736567904319114813700179347165898017864004333486947405305591758520610240861829766276798698618284354494716156033682943041579601713942220515540203161316988146991665543021307547800992939109024679837929112360581117013918612389794386017956541445146429151471384731055851996508875022310290766702717202280754490927819272344442130311818432332846202054796801431275025655264802408764738631310240751738051748559819547957257827522651952388972042708439864512706772971 +31847793196274107182845849867935019058119806419340392572260824606510195176311496560920629445019152089581060460884957727702584683631406487052881165260753582736592014907778440638252456605285448061563792096352745440411338097615871547824025696771093222358857968371367314896669453345606857912669867603377384655355233299464450205863387455153540545988356938076082061665735266055161074977243592822167126304977765007385412280214796719975406899885081155884606815348 +44462416394276340862910922260389321581298853470913371563358965890746390942505208917810214508921403677924050484037361854923909199530783769557857398908416797467991642660044081596444758567725905941578862500220928052627591160031402858547990440510112144073496748573294083122100295594485512238065152913601534980743295758670057701269862152855527112109603873427804287879276629501582896265202691196110634325565999546679242720363183998805084064278418710215080094405205990612251031795151142912 +11935289041890653422458560211344367565999989567726224393815132782921219808519438180124970259072038417888105302535754774032670805811336900569676094726678661851388189281957447472598923409448779291182901295823514011338832830575108282476521982723289897702706625317681157972521881629518687524749107700488703863037130875637878556278141428758998783243913325146240393321801800775493463196094645471464263521615496507631433273892381269104580416191455906141099074096995237227131646890810843387956035585 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +231583736816786089484927226016147767929578972263620494977377884571370600267776 +231583736816786089484927226016147767929578972263620494977377884571370600267796 +231583736816786089484927226016147767929578972263620494977377884571370600268683 +231583736816786089484927226016147767929578972264888145575244930749024664813567 +231583736816786089484927226016147767929919254630541433440841259178802368479230 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +231583736816786089484927226016147767929578972263620494977377884571370600267796 +231583736816786089484927226016147767929578972263620494977377884571370600268216 +231583736816786089484927226016147767929578972263620494977377884571370600286843 +231583736816786089484927226016147767929578972290241157532585854302105955729407 +231583736816786089484927226016147767936724901968960202710108751327437732708330 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +231583736816786089484927226016147767929578972263620494977377884571370600268683 +231583736816786089484927226016147767929578972263620494977377884571370600286843 +231583736816786089484927226016147767929578972263620494977377884571370601092239 +231583736816786089484927226016147767929578973414647237840655813881261207846911 +231583736816786089484927226016147768238555361427832619802122028119416136268915 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +231583736816786089484927226016147767929578972264888145575244930749024664813567 +231583736816786089484927226016147767929578972290241157532585854302105955729407 +231583736816786089484927226016147767929578973414647237840655813881261207846911 +231583736816786091091865264288827387140834008347669427933568389001465865175039 +231583737248145235355868446587634864434444016852318399541969024963109386715135 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +231583736816786089484927226016147767929919254630541433440841259178802368479230 +231583736816786089484927226016147767936724901968960202710108751327437732708330 +231583736816786089484927226016147768238555361427832619802122028119416136268915 +231583737248145235355868446587634864434444016852318399541969024963109386715135 +347375826054102284908498211024835675782168392195419182089908719364420193484800 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +289479781435444187096279090754304829634841333825118114339468989463902612881407 +1447400673808606139323316385517446063740088565055070501581291087314542865154047 +52801192250558338720592420408262759796307803270103458875756101126990438053445631 +73391955574979118963811141843291072273010300694702987573747700806753897109677056324904161372390199467704319 +19701003098197239571963727475337245584393210028718017492204449705694407272820256191253740390567495799714759191822335 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +347375826053891660325161479775324877793734617406404827637898376896854209069055 +2663217610796003077129846554958867075076847520262091480848308223406526385094655 +105370800764108644412417629639348963524582904761911794550729984916110487391830015 +146783911149691239803259475393503915775561367313157023134373567825771291211706236289626413008481587388481535 +39402006196322807380529480735708200350923979827639196491032590480368665196649328580283854101602350471578932714930175 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +463167473633572178969854452032295535859157944527240989954755769142741200535550 +5094842209969293968668398972355250894450737389799650889502313460570153205891050 +210509616766458555341798848448678321047987285787631029934436497075375875643407475 +293567262432083559770702660509726545373663680002960757674700605723806910944752005106341184201791019549720575 +78803862104411649792976274791681038936686527037540352976179006379866408779966168974920192682288836649583326422630400 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +3273390607896141870013189696827599152216642046043064789482248405676250539760088847507590580192374563845018358585671697709795458606968065718455598317567 +68741202765818979270276983633379582196549482966904360579127216519201261330330191061323680394341321320422430171707526206633294731198771688660155559313407 +2972238671969696817971976244719460030212710977807102828849881552354035489892114224244067263651847109974630644083661773677390487470645262366124548829478911 +4149515561151917970063980879655710938513649460124350952720371065270297197065154634382680097543307069928116034076745504813582652894960096998908020330293828836997137924009780880343039 +1113877103911668754551067286547922686738237475419584309931192581897577662915063323503306740447008536028968181678260164059239652423304638510641322142538196251906210240097862211136225475035135 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +5027927973729236057982426364448826617555638513633071601633370220421967636306978081767073880573785894184719511840282207823642068682072251874898364086616062 +105586487448313957217630953653425358968668408786294503634300774628861320362441908042372215770259805233358786793287334784851211032423969731681438233813581802 +4565358600146146340648043138919534568740519770378829014283100160143146613766526051795210258577834762925728670725464116576023894574377122961101481456204512371 +6373655901930312136397229380018411440828683949391920950832693445711366448193584697763678864931677968612065494491769987068502012729263719152592905713356550260709199907938705259972526079 +1710915231608582551713494414139930175751260546116444122900349352360496966554854730076753484481830650675467827629295454290846318941291184130710385902991584920165541896388140679840815207793295360 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +13407807929942597099574024997867385471458758537929012740010782671329620832396066576264950901075892589898837568196036807728279966661851571250364255291047934 +281563966528794539091054524955215094900633929296509267540226436097922037480312766426827633200804045843355265976758181382848606889999335438566221949106651114 +12174289600387878166413214698063586008084552752439543567929790665567295715815418404799282593193747642634147865896489293289435105940016744954024510669828652147 +16996415738478256005382065682640742151192912704409604594012987116129634408058546371285779101609491343355313845447634983424416544581829412451881265276325385337746367221507269437060808703 +4562440617622195218641171605585119131739514871918667547682857357314343535508689562160604455918497575074715174882383139717932912463990590527411215430562884597343468145381387478810284350630789120 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +26815615859885194199148049995734770942917517075858043397979502765092926124330146116347309989224671191532117255653173677432131292348064917090590289987371007 +563127933057589078182109049910430189801267858593018911357569558066951448610928436768557174051928396477654139413358055646629484729409815701210968677729435647 +24348579200775756332826429396127172016169105504879103405365388510704376920891562627194064645232838612917165822107569570980532109663098462976949750174090002431 +33992831476956512010764131365281484302385825408819231901736066162392911122587750794642859557837487570646738965348063223393520253157622555239850650779259073493783278609312973831295467519 +9124881235244390437282343211170238263479029743837341192530852050551013988199468564099149809149237792502394782872367891291382525112938685292055025133458376207627489249001013968975782644690190335 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322357114020693271444896826045989380155482288811031629873908035820404450399975636991 +225016807509116112417285197875844925210445041539832647358016193682083470938906753692021013171376104564654794171951666999009032621460467236692823685991988607159363054170329353334944355625786930020224988415478335601579539769494762759822364621043648421256660309769473452218954942169204670802030987483021311 +9729298153251306194042617127203199623384957034198478276241843041111037695834634873921670474267119187843169195625338744528581029537433535757956376518129793109557221580317097753720451186105453926588775689583539463154010576700049484340197646983155220764360535152406112288876821719552043185934730043435515903 +13582985265193575509847153720290630277475301176695966793104558898916525902171099726111653252346386417687634059875171486934990855171785554727726817192028731914702681172768151028934363876033198780003232825417916826555570603003610443324900765322801514628836605545300534605905144105325340661819603316859786269017123353358495105939406847 +3646154850295010964902624396817474390399390616036693719739415376725561063085178919082942505698777176089060633115597677023110409583667009527018497076154392047301826729011247840192495744913649306569979494349478121435366144715292958165239232610420731738086890347478554589785213505776265618736346972811536869523263453599243118147255593185837055 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463970417934507959064766276062482280155927834544016458811138434453501800557314046 +736567904319114813700179347165898017864004333486947405305591758520610240861829766276798698618284354494716156033682943041579601713942220515540203161316988146991665543021307547800992939109024679837929112360581117013918612389794386017956541445146429151471384731055851996508875022310290766702717202280754490927819272344442130311818432332846202054796801431275025655264802408764738747101888331418570393252791804927915892945979073225134359565832110399698239466 +31847793196274107182845849867935019058119806419340392572260824606510195176311496560920629445019152089581060460884957727702584683631406487052881165260753582736592014907778440638252456605285448061563792096352745440411338097615871547824025696771093222358857968371367314896669453345606857912669867603377384655355233299464450205863387455153540545988356938076082061665735266055161075093035240401847644949670737264356070345638123840811569216742473401771598281843 +44462416394276340862910922260389321581298853470913371563358965890746390942505208917810214508921403677924050484037361854923909199530783769557857398908416797467991642660044081596444758567725905941578862500220928052627591160031402858547990440510112144073496748573294083122100295594485512238065152913601534980743295758670057701269862152855527112109603873427804287879276629501582896265202691196110634325565999662470890300043702643498056321249076775638407215241368307469643277682142609407 +11935289041890653422458560211344367565999989567726224393815132782921219808519438180124970259072038417888105302535754774032670805811336900569676094726678661851388189281957447472598923409448779291182901295823514011338832830575108282476521982723289897702706625317681157972521881629518687524749107700488703863037130875637878556278141428758998783243913325146240393321801800775493463196094645471464263521615496507631433389684028848785099060884428163111757139520322358063293963748203089274947502080 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049793 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049813 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998050700 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725447442614227457227324739062595584 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656433007813095902093053555754516766261247 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049813 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998050233 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998068860 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725472795626184798150877820353511424 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590663238655151514671362321047903152130490347 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998050700 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998068860 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998874256 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092726597201706492868110456975605628928 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590965069114610387088454334324695130534050932 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725447442614227457227324739062595584 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725472795626184798150877820353511424 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092726597201706492868110456975605628928 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804492314385376101550209867347761530223896585780685577180262957056 +3273390607896141870013189696827599152216642046043064789482248405676250539528505111122163636578388558400357687160957770034872868194181321538823784497152 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656433007813095902093053555754516766261247 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590663238655151514671362321047903152130490347 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590965069114610387088454334324695130534050932 +3273390607896141870013189696827599152216642046043064789482248405676250539528505111122163636578388558400357687160957770034872868194181321538823784497152 +3273390607896141870013189696827599152216642046043064789482248405676250539644297199928120686131018322837558498508682145377973650742121015940134591266817 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +3273390607896141870013189696827599152216642046043064789482248405676250539586401155309462588318799202567027652361355087007672582991681286039617010663424 +3273390607896141870013189696827599152216642046043064789482248405676250540744322047682624540545836497330168886466602318237624970233503383890257262936064 +3273390607896141870013189696827599152216642046043064789482248405676250592098113624432357121814940520075482619034317023286013344408313423566152451227648 +3273390607896141870013189696827599152216642119435020364461367369487392382587993646884319095925507685560423629480410862859610793556373668965913865486336 +3273390607896141870013189696827599171917645144240304361445975881013496123690131402592035893426969817507130095546769944436294859219708096290473589604352 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +3273390607896141870013189696827599152216642046043064789482248405676250539644297199927910061547681591588047700520248370588959296290110673472568606851072 +3273390607896141870013189696827599152216642046043064789482248405676250541960138984670021478352366666771589897803361273444645949500520519982240782876672 +3273390607896141870013189696827599152216642046043064789482248405676250644667722137982662813640149751161686347309418515094349019382197212686201789612032 +3273390607896141870013189696827599152216642192826975939173488208935725932800837149435385714379543246186290648497804964888790758278625305057301786263552 +3273390607896141870013189696827599191618648242365872170011729141384450890220901201513214892255110592181388019375842333466408570254562768154647112712192 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +3273390607896141870013189696827599152216642046043064789482248405676250539760088847507590580192374563845018358585671697709795458606968065718455598317567 +3273390607896141870013189696827599152216642046043064789482248405676250544391763583843312369890919084167973717177251142982205358154525757145867603673067 +3273390607896141870013189696827599152216642046043064789482248405676250749806538140332573743021368560491043870713799540813584403088709371951590041189492 +3273390607896141870013189696827599152216642339610327221565808176378911049023466747537698404183277786513328546533424697934559574993396498366733947502592 +3273390607896141870013189696827599231020504150454714582458523197357289475983448411414371377401526491679131602692682728102747150941048946159040820412417 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +6546781215792283740026379393655198304433284092086129578964496811352501079057010221381608981414894675657741181312185450892349927259180362294169996099584 +72014593373715121140290173330207181348766125012947425368609464924877511869627112435197698795563841432235152994434039959815849199850983985235869957095424 +2975512062577592959841989434416287629364927619853145893639363800759711740431411145617941282053069630086443366906388287430573041939297474662700263227260928 +4149515561151917970063980879658984329121545601994364142417198664422513839111197699172162345948983320467412955450619523214805173006772819821634534083476383305649350220585495278125056 +1113877103911668754551067286547922686741510866027480451801205771594405262067279965549349805236490784434644432217557085433113670824527158622454044965264710005088764708750074507711939872817152 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +5031201364337132199852439554145654216707855155679114666422852468827643886846275003140947898975008414296532234663008721576824623150724464171474078484398079 +105589760838921853359500966843122186567820625428340546699090256877266996612981204963746089788661027753470599516110061298604393586892621943978013948211363819 +4565361873536754236789913152109231396339671987020875057347889642391552290017065348716584132596235985445840483448286843089777077128845775173398057170602294388 +6373655901930312136397229380018414714219291845533790964022390273310518664835630740828468347180083644862604791413143861086903235249375531875415632227109732815177852120235280974370308096 +1710915231608582551713494414139930175751263819507052019042219365550193794154006946718799527546620132923873503879834751212220192959692406650822198625814311433918724450856792892137390922191077377 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +13411081320550493241444038187564213070610975179975055804800264919735297082935363497638824919477115110010650291018763321481462521130503783546939969688829951 +281567239919402435232924538144911922499786145938555310605015918346327713730852063348201507219205268363467078699580907896601789444467987650862797663504433131 +12174292873778486062555084711253282835683704969081589610994580147815701392065957701720656467212148865154259678619312019803188288494485397166321086384226434164 +16996415738478256005382065682640745424583520600551474607202683943728786624700592414350568583857897019605853142369008857442817767101941225174703991790078567892215019433803845151458590720 +4562440617622195218641171605585119131739518145309275443824727370504040363107841778802650498983287057323120851132922436639306786482391813047523028153385611111096650699850039691106860065028571137 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +26818889250493090341018063185431598542069733717904086462768985013498602374869443037721184007625893711643929978475900191185313846816717129387166004385153024 +563131206448196974323979063100127017400420075235064954422359040315357124861467733689931048070329618997765952136180782160382667283878467913507544392127217664 +24348582474166364228968299409316868843768257721521149448430177992952782597142101924115438519251239835437277634830392297494285292217567115189246325888487784448 +33992831476956512010764131365281487575776433304961101914925762989992063339229796837707649040085893246897278262269437097411921475677734367962673377293012256048251930821609549545693249536 +9124881235244390437282343211170238263479033017227949088672722063740710815798620780741195852214027274750800459122907188212756399131339907812166837856281102721380671803469666181272358359087972352 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094859873731529946340457125253265606438475403785866280608383688705623749572896410942067145463298048566101192878305015324784812428376688032701026114373419008 +225016807509116112417285197875844925210445041539832647358016193682083470938906753692021013171376104564654794171951666999009032621460467236692823685991991880549970950312199366524641183224939146662271031480267817849985216020034059681196238639444870941368473032592199965972137496637856883098606701880803328 +9729298153251306194042617127203199623384957034198478276241843041111037695834634873921670474267119187843169195625338744528581029537433535757956376518129796382947829476458967766910148013704606143230821732648328945402416252950588781261571521001556443284472347875228838802630004274020695398231305757833297920 +13582985265193575509847153720290630277475301176695966793104558898916525902171099726111653252346386417687634059875171486934990855171785554727726817192028731914702681172768151028934367149423806676145102838607613654154722819645656486389690247571207190879375902466674408624306366625437153384642329830612968823485775565655070820337188864 +3646154850295010964902624396817474390399390616036693719739415376725561063085178919082942505698777176089060633115597677023110409583667009527018497076154392047301826729011247840192495744913652579960587390491348134625062972314445174807285275675210213986492566598017851511159087524177488138848159695634263383276446008067895330443831307583619072 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988312365191525626829590504228669795829923743060941349315981180118158171906003267339308381977465988796174295002978654348297199013279790646750077514955096063 +736567904319114813700179347165898017864004333486947405305591758520610240861829766276798698618284354494716156033682943041579601713942220515540203161316988146991665543021307547800992939109024679837929112360581117013918612389794386017956541445146429151471384731055851996508875022310290766702717202280754494201209880240584000325008129160445354271438847474339815137513208085015278044023262205436971615772903617650738619459732255779603011778128686114096021483 +31847793196274107182845849867935019058119806419340392572260824606510195176311496560920629445019152089581060460884957727702584683631406487052881165260753582736592014907778440638252456605285448061563792096352745440411338097615871547824025696771093222358857968371367314896669453345606857912669867603377384658628623907360592075876577151981139698204998984119146851147983671731411614389956614275866046172190849077078893072151877023366037868954769977485996063860 +44462416394276340862910922260389321581298853470913371563358965890746390942505208917810214508921403677924050484037361854923909199530783769557857398908416797467991642660044081596444758567725905941578862500220928052627591160031402858547990440510112144073496748573294083122100295594485512238065152913601534980743295758670057701269862156128917720005745743440993984706875781718224942308267480678359040001816538959392264174062103866018168133971899502152160397795836959681939853396540391424 +11935289041890653422458560211344367565999989567726224393815132782921219808519438180124970259072038417888105302535754774032670805811336900569676094726678661851388189281957447472598923409448779291182901295823514011338832830575108282476521982723289897702706625317681157972521881629518687524749107700488703863037130875637878556278141428758998786517303933042382263334991497603092615412736691514529053003863902183881972686605402722803500283404539975834579866034075540617762615960499664989345284097 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348288 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348308 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486349195 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851379715837692741036504647550894079 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352969133745369125558337364934425254559742 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348308 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348728 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486367355 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851405068849650081960057728841809919 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072359774781083787894827604857083060618788842 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486349195 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486367355 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993487172751 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628852529474929958151919636884093927423 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072661605240542660311919618133875039022349427 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851379715837692741036504647550894079 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851405068849650081960057728841809919 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628852529474929958151919636884093927423 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094485907904996976043691563883887462497120051064494757088751255551 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030688453630171908179274851168857493895967146091659465130718732272795647 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352969133745369125558337364934425254559742 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072359774781083787894827604857083060618788842 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072661605240542660311919618133875039022349427 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030688453630171908179274851168857493895967146091659465130718732272795647 +5027927973729236057982426364448826617555638513633071601633370220421967636306862290119494410679724537943712051980205218271310246874207404825120043079565312 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +5027927973729236057982426364448826617555638513633071601633370220421967636306804394074875752581912318823441521134057891212939945806456965095219525498961919 +5027927973729236057982426364448826617555638513633071601633370220421967636307962314967248914534139356118204662368163138444169898193698787193070165751234559 +5027927973729236057982426364448826617555638513633071601633370220421967636359316106543998647115408460140949976100730853149218286567873597232746060939526143 +5027927973729236057982426364448826617555638513706463557208349339385778778149805986566450609089519027306434917111176946988791884017021657478145822353784831 +5027927973729236057982426364448826617575339516731268841205333947897304881890908124322158325887020489438381623577243306070368568082684991905470382077902847 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +5027927973729236057982426364448826617555638513633071601633370220421967636306862290119494200055141201212462541182216784496521232519755394482652477095149567 +5027927973729236057982426364448826617555638513633071601633370220421967636309178131904236311471945886287646083379499897399376919172965804329162149271175167 +5027927973729236057982426364448826617555638513633071601633370220421967636411885715057548952807233669372036179829005954641026622242847481021866110277910527 +5027927973729236057982426364448826617555638513779855512783061460225227111700018830069001675707973062867060784130194341090821063981743909114237210274562047 +5027927973729236057982426364448826617595040519829394409013899701157675836657438894121079504885848630213055881501072378459398681793719846577334555601010687 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +5027927973729236057982426364448826617555638513633071601633370220421967636306978081767073880573785894184719511840282207823642068682072251874898364086616062 +5027927973729236057982426364448826617555638513633071601633370220421967636311609756503409602363484438705042467198873787268914478581619809566325776091971562 +5027927973729236057982426364448826617555638513633071601633370220421967636517024531059898863736614888181365537352410335666745857626553993181131498529487987 +5027927973729236057982426364448826617555638513926638864065453780192670296816241459667103988397776797407387822028229960823866832798458680307546642435801087 +5027927973729236057982426364448826617634442375737483251426346495213648675243201441330980661370995046112553625084389218854035020374406332755338949308710912 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +5031201364337132199852439554145654216707855155679114666422852468827643886846275003140947898975008414296532234663008721576824623150724464171474078484398079 +5096669176495055037252703348082206199752187996599975962212497436941168897636845105354763988789157361053109646476130576085748122423316267794415778445393919 +8000166645698932875954402609168286647768349491440174430483251772776003126198629138537507572046663149707317860388084823556505315162762758471880171715559423 +4149515561151917970063980884683638912242885518106777317169197682825935710698226236016050317965274706234630948370185813208398692627647313303331070209408656529114634029765403766423551 +1113877103911668754551067286547922691766165449148820367913618946346404280470701837136378342080378756450935817984775078352679960818120678243328538446961246131021037932215358316891848361115647 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +10055855947458472115964852728897653235111277027266143203266740440843935272613492996060514188968601933917406728144705257702756896374189747980653986972696574 +110614415422043193275613380017874185586224047299927575235934144849283287998748422956665656078654621273091474009591757834730325860116087227787193856699662314 +4570386528119875576706025565283983395358075408892462085884733530363568581402832566709503698886229578965461357941768539625903009402069240457207237079090592883 +6373655901930312136397229380023439368802413185449903377197142272328922086707217769365312235152099936248372009406063427376896828768996406368897328763235665088401317404044460882858606591 +1710915231608582551713494414139930175756288474090173358958331778724945793172410368590386556083464020895889795265601969205139759249686000170443073119296007970044656724080258175946570830679375872 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +18435735903671833157556451362316212089014397051562084341644152891751588468702581490558391209470708629631524784500459857607394794353969067356119878177128446 +286591894502523775149036951319663921518189567810142339141859806318344005116619281341121073509198861883087953193062604432727721717691452934671977571992731626 +12179317528361607402471197124428034834702108390953176639531424035787717683451724919713576033502142458673880553112793716339314220767708862450130266292714732659 +16996415738478256005382065682645770079166641940467587020377435942747190046572179442887412471829913310991620360361928423732811360621562099668185688326204500165438484717613025059946889215 +4562440617622195218641171605585119131744542799892396783740839783678792362126245200674237527520130945295137142518689654632226352772385406567143902646867307647222582973073504974916039973516869632 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +31843543833614430257130476360183597560473155589491114999612872985514893760636661030640750297619487231264804471957596727311246120040182413196345912873451519 +568155861031318314240091476274879016418823497106651982959202928287373416247234951682850614360323212517386826629662478696508599557101933197316724300615516159 +24353607128749485568884411822491620842786661143392736476967021880924798888527869142108358085541233428956898509323873994030411224490790580473055505796976082943 +33992831476956512010764131365286512230359554644877214328100514989010466761101383866244492928057909538283045480262356663701915069197355242456155073829138188321475396105418729454181548031 +9124881235244390437282343211170238263484057671811070428588834476915462814817024202612782880750871162722816750508674406205675965421333501331787712349762799257506604076693131465081538267576270847 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604099884528314651286256569538428017605456878825657453309145227576677640040958663628934986711753291642085722067371786711860910744701600153316510206022861717503 +225016807509116112417285197875844925210445041539832647358016193682083470938906753692021013171376104564654794171951666999009032621460467236692823685997016535133092290228311779699393182243342568533858060017111705822001507405801277674115804929438464460989347526073896502098069769861322166907786610369101823 +9729298153251306194042617127203199623384957034198478276241843041111037695834634873921670474267119187843169195625338744528581029537433535757956376518134821037530950816375080180084900012723009565102408761185172833374432544336355999254491087291550036804093222368710535338755936547244160682040485666321596415 +13582985265193575509847153720290630277475301176695966793104558898916525902171099726111653252346386417687634059875171486934990855171785554727726817192028731914702681172768151028939391804006928016061215251782365653173126241517243514926534135543223482265143120459593974914299960145058027878124026366738901096709240849464250728825487359 +3646154850295010964902624396817474390399390616036693719739415376725561063085178919082942505698777176089060633115597677023110409583667009527018497076154392047301826729011247840192495744918677234543708730407460547799814971332848596678872304212054101958508857983785069504078653814171081658469034189115959919402378281291360614253011216071917567 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060993337019774646966745702917403421794848327164932528377852825068090174463291770485332227948267459582315795169496460350884423131286503255930559257423443394558 +736567904319114813700179347165898017864004333486947405305591758520610240861829766276798698618284354494716156033682943041579601713942220515540203161316988146991665543021307547800992939109024679837929112360581117013918612389794386017956541445146429151471384731055851996508875022310290766702717202280759518855793001580500112738182881159463757693310434502876659025485224376401045262016181771726965209292524492144220315995858188052826477061937866022584319978 +31847793196274107182845849867935019058119806419340392572260824606510195176311496560920629445019152089581060460884957727702584683631406487052881165260753582736592014907778440638252456605285448061563792096352745440411338097615871547824025696771093222358857968371367314896669453345606857912669867603377389683283207028700508188289751903980158101626870571147683695035955688022797381607949533842156039765710469951572374768688002955639261334238579157394484362355 +44462416394276340862910922260389321581298853470913371563358965890746390942505208917810214508921403677924050484037361854923909199530783769557857398908416797467991642660044081596444758567725905941578862500220928052627591160031402858547990440510112144073496748573294083122100295594485512238065152913601534980743295758670057701269867180783500841345661855854168736705894185140096529336804324566331056293202306177385183740352097459537789008465381198688286330069060424965749033305028689919 +11935289041890653422458560211344367565999989567726224393815132782921219808519438180124970259072038417888105302535754774032670805811336900569676094726678661851388189281957447472598923409448779291182901295823514011338832830575108282476521982723289897702706625317681157972521881629518687524749107700488703863037130875637878556278141428759003811171887054382298375748166249602111018834608278543065896891835918475267739904598322289093493876924160850328061562570201472890986081244308844897833582592 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780160 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780180 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690781067 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756017613817472060411970538755325951 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107569038383267105337656740400316458991614 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780180 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780600 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690799227 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756042966829429401335523620046241791 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428114374685721685874606924232548951823220714 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690781067 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690799227 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884691604623 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228757167372909737471295102775298359295 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428416205145180558291698937509340930226781299 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756017613817472060411970538755325951 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756042966829429401335523620046241791 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228757167372909737471295102775298359295 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114988014600711094100047318483792100395099830383870222979955687423 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528565474132278603893392907524612093800605044071438784506184623477227519 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107569038383267105337656740400316458991614 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428114374685721685874606924232548951823220714 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428416205145180558291698937509340930226781299 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528565474132278603893392907524612093800605044071438784506184623477227519 +13407807929942597099574024997867385471458758537929012740010782671329620832395950784617371431181831233657830108335959818175948144853986724200585934283997184 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +13407807929942597099574024997867385471458758537929012740010782671329620832395892888572752773084019014537559577489812491117577843786236284470685416703393791 +13407807929942597099574024997867385471458758537929012740010782671329620832397050809465125935036246051832322718723917738348807796173478106568536056955666431 +13407807929942597099574024997867385471458758537929012740010782671329620832448404601041875667617515155855068032456485453053856184547652916608211952143958015 +13407807929942597099574024997867385471458758538002404695585761790293431974238894481064327629591625723020552973466931546893429781996800976853611713558216703 +13407807929942597099574024997867385471478459541027209979582746398804958077979996618820035346389127185152499679932997905975006466062464311280936273282334719 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +13407807929942597099574024997867385471458758537929012740010782671329620832395950784617371220557247896926580597537971384401159130499534713858118368299581439 +13407807929942597099574024997867385471458758537929012740010782671329620832398266626402113331974052582001764139735254497304014817152745123704628040475607039 +13407807929942597099574024997867385471458758537929012740010782671329620832500974209555425973309340365086154236184760554545664520222626800397332001482342399 +13407807929942597099574024997867385471458758538075796651160473911132880307789107324566878696210079758581178840485948940995458961961523228489703101478993919 +13407807929942597099574024997867385471498160544125335547391312152065329032746527388618956525387955325927173937856826978364036579773499165952800446805442559 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +13407807929942597099574024997867385471458758537929012740010782671329620832396066576264950901075892589898837568196036807728279966661851571250364255291047934 +13407807929942597099574024997867385471458758537929012740010782671329620832400698251001286622865591134419160523554628387173552376561399128941791667296403434 +13407807929942597099574024997867385471458758537929012740010782671329620832606113025557775884238721583895483593708164935571383755606333312556597389733919859 +13407807929942597099574024997867385471458758538222580002442866231100323492905329954164981008899883493121505878383984560728504730778237999683012533640232959 +13407807929942597099574024997867385471537562400033424389803758946121301871332289935828857681873101741826671681440143818758672918354185652130804840513142784 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +13411081320550493241444038187564213070610975179975055804800264919735297082935363497638824919477115110010650291018763321481462521130503783546939969688829951 +13476549132708416078844301981500765053655308020895917100589909887848822093725933599852641009291264056767227702831885175990386020403095587169881669649825791 +16380046601912293917546001242586845501671469515736115568860664223683656322287717633035384592548769845421435916743839423461143213142542077847346062919991295 +4149515561151917970063980893063518868456246559698375950587756536729055734994167374393462768872927902323719442868062833710505388341765369659085670114046554508893953405231294970855423 +1113877103911668754551067286547922700146045405362181409505217579764963134373821861432319480457791207358589014073863572850556981320227373957446594802715846035658935911994677692357739565547519 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +18435735903671833157556451362316212089014397051562084341644152891751588468702581490558391209470708629631524784500459857607394794353969067356119878177128446 +118994295378256554317204978651292744440127167324223516374311557300190941194837511451163533099156727968805592065947512434634963758095866547162659747904094186 +4578766408076088937747617163917401954211978528916758027023110942814476234598921655204001575906731685661175475998124294225807647300049019776582702970295024755 +6373655901930312136397229380031819248758626546491494975830560831182825206731513710503689647603007589444461097900561304397398935464710524425253083363140302986381096723419926774063038463 +1710915231608582551713494414139930175764668354046386719999923377358364352026313488614682497221841433346797448461691057699637636270188106866157191175651762569949294622060037495322036721883807744 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +26815615859885194199148049995734770942917517075858025480021565342659241664791669985056268229972815325345642840856214457512032692333748386731585769381560318 +294971774458737136190628549953082480372092687834438280280237218769251658312708369835618950529700968578802071249418359032632359615671232254047443463197163498 +12187697408317820763512788723061453393556011510977472580669801448238625336647814008208073910522644565369594671169149470939218858665688641769505732183919164531 +16996415738478256005382065682654149959122855301509178619010854501601093166596475384025789884280820964187709448856426300753313467317276217724541442926109138063418264036988490951151321087 +4562440617622195218641171605585119131752922679848610144782431382312210920980148320698533468658508357746044795714778743126724229792887513262858020703223062247127220871053284294291505864721301504 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +40223423789827791298722074993602156414376275613787056137990285436422546956725749525138627318121593926978922528313351327215884018019961732571811804077883391 +576535740987531675281683074908297575272726617130947924097580340738281069443324040177348491380825319213100944686018233296413237455081712516692190191819948031 +24361987008705698929926003421125039401640564263417032418105399293375706541723958230602855962561735535652612627380229748630315862388770359792430971688180514815 +33992831476956512010764131365294892110315768005918805926733933547864369881125679807382870340508817191479134568756854540722417175893069360512510828429042826219455175424794195345385979903 +9124881235244390437282343211170238263492437551767283789630426075548881373670927322637078821889248575173724403704763494700173842441835608027501830406118553857411241974672910784457004158780702719 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604108264408270864647298161137061436164310781945681749250283604989128547694154752717429484588773793748781436185428142466460815382599579932635885671914066149375 +225016807509116112417285197875844925210445041539832647358016193682083470938906753692021013171376104564654794171951666999009032621460467236692823686005396415089305651269903378332811741097245688558154001155489118272909160601890366168613681949940571156703465582429651102002707667841101486283252501573533695 +9729298153251306194042617127203199623384957034198478276241843041111037695834634873921670474267119187843169195625338744528581029537433535757956376518143200917487164177416671778718318571576912685126704702323550245825340197532445087748988964312052143499807340425066289938660574445223940001415951557526028287 +13582985265193575509847153720290630277475301176695966793104558898916525902171099726111653252346386417687634059875171486934990855171785554727726817192028731914702681172768151028947771683963141377102806850415784212027029361541539456064911547994131135461232208954091851934802066840772145934479780966643538994689020168839716620029919231 +3646154850295010964902624396817474390399390616036693719739415376725561063085178919082942505698777176089060633115597677023110409583667009527018497076154392047301826729011247840192495744927057114499922091449052146433233530186751716703168245350431514409416511179874157998576530834673188354183152245471714519307016179271139933628477107276349439 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581061001716899730860327787294516036840353702230284956824318991202480541082116487859573826725825287961689011509287552816105484327769184483035249934723314647826430 +736567904319114813700179347165898017864004333486947405305591758520610240861829766276798698618284354494716156033682943041579601713942220515540203161316988146991665543021307547800992939109024679837929112360581117013918612389794386017956541445146429151471384731055851996508875022310290766702717202280767898735749214941541704336816299718317660813334730444015036437936132029597134350510679648747467315988238610200576070595762825950806256381313331913788751850 +31847793196274107182845849867935019058119806419340392572260824606510195176311496560920629445019152089581060460884957727702584683631406487052881165260753582736592014907778440638252456605285448061563792096352745440411338097615871547824025696771093222358857968371367314896669453345606857912669867603377398063163163242061549779888385322539012004746894867088822072448406595675993470696444031719176541872406184069628730523287907593537241113557954623285688794227 +44462416394276340862910922260389321581298853470913371563358965890746390942505208917810214508921403677924050484037361854923909199530783769557857398908416797467991642660044081596444758567725905941578862500220928052627591160031402858547990440510112144073496748573294083122100295594485512238065152913601534980743295758670057701269875560663457054706703447452802155264748088260120825277942701978781963946398395265879681617372599566233503126521736953288190967967040204285124499196233121791 +11935289041890653422458560211344367565999989567726224393815132782921219808519438180124970259072038417888105302535754774032670805811336900569676094726678661851388189281957447472598923409448779291182901295823514011338832830575108282476521982723289897702706625317681157972521881629518687524749107700488703863037130875637878556278141428759012191051843267743339967346799668160964921954632574484204274304286826128463828993092820166113995983619874968384417317170106110788965860563684310789038014464 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103233 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103253 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387104140 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459868939503685406252196573451649024 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244438742234592791551002580626351155314687 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103253 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103673 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387122300 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459894292515642747175749654742564864 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885251244389573011560820270072774986519543787 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387104140 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387122300 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387927696 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098461018698595950817135328809994682368 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885553074849031883977912283349566964923104372 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459868939503685406252196573451649024 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459894292515642747175749654742564864 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098461018698595950817135328809994682368 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203136793202344373787504455353495951720786043729710449014652010496 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610924562281057205526672594981748963504456369757652130346410658173550592 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244438742234592791551002580626351155314687 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885251244389573011560820270072774986519543787 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885553074849031883977912283349566964923104372 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610924562281057205526672594981748963504456369757652130346410658173550592 +26815615859885194199148049995734770942917517075858043397979502765092926124330030324699730519330609835291109795793096687879799470540200070040811968980320257 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +26815615859885194199148049995734770942917517075858043397979502765092926124329972428655111861232797616170839264946949360821429169472449630310911451399716864 +26815615859885194199148049995734770942917517075858043397979502765092926124331130349547485023185024653465602406181054608052659121859691452408762091651989504 +26815615859885194199148049995734770942917517075858043397979502765092926124382484141124234755766293757488347719913622322757707510233866262448437986840281088 +26815615859885194199148049995734770942917517075931435353554481884056737266172974021146686717740404324653832660924068416597281107683014322693837748254539776 +26815615859885194199148049995734770942937218078956240637551466492568263369914076158902394434537905786785779367390134775678857791748677657121162307978657792 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +26815615859885194199148049995734770942917517075858043397979502765092926124330030324699730308706026498559860284995108254105010456185748059698344402995904512 +26815615859885194199148049995734770942917517075858043397979502765092926124332346166484472420122831183635043827192391367007866142838958469544854075171930112 +26815615859885194199148049995734770942917517075858043397979502765092926124435053749637785061458118966719433923641897424249515845908840146237558036178665472 +26815615859885194199148049995734770942917517076004827309129194004896185599723186864649237784358858360214458527943085810699310287647736574329929136175316992 +26815615859885194199148049995734770942956919082054366205360032245828634324680606928701315613536733927560453625313963848067887905459712511793026481501765632 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +26815615859885194199148049995734770942917517075858043397979502765092926124330146116347309989224671191532117255653173677432131292348064917090590289987371007 +26815615859885194199148049995734770942917517075858043397979502765092926124334777791083645711014369736052440211011765256877403702247612474782017701992726507 +26815615859885194199148049995734770942917517075858043397979502765092926124540192565640134972387500185528763281165301805275235081292546658396823424430242932 +26815615859885194199148049995734770942917517076151610660411586324863628784839409494247340097048662094754785565841121430432356056464451345523238568336556032 +26815615859885194199148049995734770942996320937962455047772479039884607163266369475911216770021880343459951368897280688462524244040398997971030875209465857 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +26818889250493090341018063185431598542069733717904086462768985013498602374869443037721184007625893711643929978475900191185313846816717129387166004385153024 +26884357062651013178418326979368150525114066558824947758558629981612127385660013139935000097440042658400507390289022045694237346089308933010107704346148864 +29787854531854891017120026240454230973130228053665146226829384317446961614221797173117743680697548447054715604200976293164994538828755423687572097616314368 +4149515561151917970063980906471326798398843659272400948455142008187814272923198032362182862636233194257798982950421921859283989975045057116222539817897880195107299245457329667178496 +1113877103911668754551067286547922713553853335304778509079242577632348605832580399361350138426511301121894306007943112932916069469005975590726282259852715739510261598208023532583774261870592 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +31843543833614430257130476360183597560473155589491114999612872985514893760636661030640750297619487231264804471957596727311246120040182413196345912873451519 +132402103308199151416779003649160129911585925862152547032280277393954246486771590991245892187305506570438871753404649304338815083782079893002885782600417259 +4592174216006031534847191188915269339683437287454687057681079662908239539890855734744083934994880464262808755685581431095511498625735233122422929004991347828 +6373655901930312136397229380045227056688569143591069000828428216654283965269442741161658367696770894736395177440643663485547714066343804112710220232844154312067310069260152808759361536 +1710915231608582551713494414139930175778076161976329317099497402356231737497772247152611527879810153440560753753625137239719995358336885467790470863108899439653145947746250841162262756580130817 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +40223423789827791298722074993602156414376275613787056137990285436422546956725749525138627318121593926978922528313351327215884018019961732571811804077883391 +308379582388679733290202574950949865843551446372367310938205938863014963604642449375701309617849747180435350936875495902336210941357445599887669497893486571 +12201105216247763360612362748059320779027470269515401611327770168332388641939748087748156269610793343971227950856606607808922709991374855115345958218615487604 +16996415738478256005382065682667557767052797898608752644008721887072551925134404414683758604374584269479643528396508659841462245918909497411998579795812989389104477382828716985847644160 +4562440617622195218641171605585119131766330487778552741882005407310078306451607079236462499316477077839808101006712822666806588881036291864491300390680199116831072196739497640131731899417624577 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +53631231719770388398296099991469541885835034151716086795959005530185852248659829065220986406270372528612202215770488196919735343706175078412037838774206464 +589943548917474272381257099906164960744185375668876954755549060832044374735258119717430850468974097814734224373475370166117088780767925862532416226516271104 +24375394816635641527025577446122906787112023021954961448763368013469469847015892310142938321649884314254245907067686885500019713714456573138271197722876837888 +33992831476956512010764131365308299918245710603018379951731800933335828639663608838040839060602580496771068648296936899810565954494702640199967965298746677545141388770634421380082302976 +9124881235244390437282343211170238263505845359697226386730000100546748759142386081175007852547217295267487708996697574240256201529984386629135110093575690727115093300359124130297230193477025792 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604121672216200807244397735162059303549782240704219678280941573709222310999446686796969566947861942527383069465115599603330519233925266145981725897948762472448 +225016807509116112417285197875844925210445041539832647358016193682083470938906753692021013171376104564654794171951666999009032621460467236692823686018804223019248248369477403330679126568704447096083031813457838366672465893824445708696041038089349758336745269886787971706558993527314832123478536269856768 +9729298153251306194042617127203199623384957034198478276241843041111037695834634873921670474267119187843169195625338744528581029537433535757956376518156608725417106774516245803716185957048371443664633732981518965919103502824379167289071323400200922101440620112523426808364425770910153347256177592222351360 +13582985265193575509847153720290630277475301176695966793104558898916525902171099726111653252346386417687634059875171486934990855171785554727726817192028731914702681172768151028961179491893083974202380875413651597498488120079468486722880268087894440753166288494174211022950845442405425621936917836347390320375233514679942654726242304 +3646154850295010964902624396817474390399390616036693719739415376725561063085178919082942505698777176089060633115597677023110409583667009527018497076154392047301826729011247840192495744940464922429864688548626171431100915658210475241097276008400234503179816471808237538658889922821966955816431932928851389010867504957353279468703141972672512 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581061015124707660802924886868541034707739173689043494753349649171200634845421779793653366808184376110467613142567240273242354031620510169248595774949349344149503 +736567904319114813700179347165898017864004333486947405305591758520610240861829766276798698618284354494716156033682943041579601713942220515540203161316988146991665543021307547800992939109024679837929112360581117013918612389794386017956541445146429151471384731055851996508875022310290766702717202280781306543679157538641278361814167103789119571872659474673005158029895334889068430050762007835616094589871889888033207465466677276492469727153557948485074923 +31847793196274107182845849867935019058119806419340392572260824606510195176311496560920629445019152089581060460884957727702584683631406487052881165260753582736592014907778440638252456605285448061563792096352745440411338097615871547824025696771093222358857968371367314896669453345606857912669867603377411470971093184658649353913383189924483463505432796119480041168500358981285404775984114078264690651007817349316187660157611444862927326903794849320385117300 +44462416394276340862910922260389321581298853470913371563358965890746390942505208917810214508921403677924050484037361854923909199530783769557857398908416797467991642660044081596444758567725905941578862500220928052627591160031402858547990440510112144073496748573294083122100295594485512238065152913601534980743295758670057701269888968471386997303803021477800022650219547018658754308600670698875727251690329345419763976460748344835136406209194090157894819292726417630964725230929444864 +11935289041890653422458560211344367565999989567726224393815132782921219808519438180124970259072038417888105302535754774032670805811336900569676094726678661851388189281957447472598923409448779291182901295823514011338832830575108282476521982723289897702706625317681157972521881629518687524749107700488703863037130875637878556278141428759025598859773210340439541371797535546436380713170503514862243024380589433755763072632902525202144762221508248071874454039809962114652073909524536823734337537 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369217 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369237 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375370124 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059367521063656309566056683439915008 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359572341733174351521905894486461143580671 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369237 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369657 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375388284 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059392874075613650489609764730830848 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714366377989071593120791173386635096507809771 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375370124 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375388284 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029376193680 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232060517280155921720449188919982948352 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714668208448530465537883186663427074911370356 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059367521063656309566056683439915008 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059392874075613650489609764730830848 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232060517280155921720449188919982948352 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658808948056801636687333570487095450302346014633024309124640276480 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956886017953212059983935494810864097103954951317623033660270768161816576 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359572341733174351521905894486461143580671 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714366377989071593120791173386635096507809771 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714668208448530465537883186663427074911370356 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956886017953212059983935494810864097103954951317623033660270768161816576 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356998229045691975002764689748372695622211821479298052100170973354672078968586241 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356940333001073316904952470628102164776064494420927751032420533624771561387982848 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322358098253893446478857179507922865306010169741652157703419662355722622201640255488 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322409452045470196211438448611945610619742737456357206091793837165762298096828547072 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143893629499169185576181884464199941925492648173412559179111095560753183550196779689242985226007697858242805760 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839342888146918434783166170184693410567941044063248355890210060641243042267219249909278356373308648560435022417966923776 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356998229045691764378181353017123184824223387704509037745718963012204512984170496 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322359314070830433875794986038092306727021506500607364724398929372858714185160196096 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322462021653983746517130273821176696823471012557849014427468811049551418146166931456 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143967021454743897697021332797750154768995199240031013214671721427772200944298808869207707477643789246163582976 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839362589150016560350974735937953781522707574833047277069208888782017716525143078981667386487019683415106886591490031616 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322357114020693271444896826045989380155482288811031629873908035820404450399975636991 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322361745695429607166686524590509703110840880390476902283807583378095877811980992491 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322567160469986096428059655039986026180994416938874733662852517561710683534418508916 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187144113804806026290016988775982866377398593301552720816949212048465670236564031854638024422248837098678324822016 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839401991005924649193387182732009754361293337380257178225694035197917214268726395822062022825600369901284890985197731841 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094859873731529946340457125253265606438475403785866280608383688705623749572896410942067145463298048566101192878305015324784812428376688032701026114373419008 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094925341543687869177857389047202158421519736626787141904173333673737274583686981044280961553112197512857770290118137179293735927649279836323967814334414848 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604097828839012891747016559088308288238869535898121627340372444088009572108812248765077463705136369703301511978504030091426764493120388726327001432207604580352 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714242674878487840834003055584974512311279435699658711463016289149904593484340885392177976886554761380392284766887296383377531438844432307956945337673417396461755078202559317439655444480 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246284526591342437031681239983319539526781594837816341634508518304645466356502238250467323544284041214993247041504034911017278877525141160830047989182088967849339008843158178926846443884250136576 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604099884528314651286256569538428017605456878825657453309145227576677640040958663628934986711753291642085722067371786711860910744701600153316510206022861717503 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604200443087789236007416218065716994137807991595930114741177894981086079393684798558895591853642977661424896134653233764437938313665342050796316745892588683243 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991608660215200487068390846630250983103347579842957522649251826694366600364687088882702648429896450552619117266018585410546229110997207295204025736789114979613812 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412720612181264857001052430220984113268041169605999590508062896262224550689635337404935307273071388896041934422145344989624941219868920801067012539335366443652893627280972574012918747627520 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609247994327945847107914640183330172921779846117146457366173098936464424065745394177917220573722025424857132685900951652105144065956814009040322247733762938014573252644529306221744476122866568396801 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604108264408270864647298161137061436164310781945681749250283604989128547694154752717429484588773793748781436185428142466460815382599579932635885671914066149375 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604376420566869716589289641637018783873739957116440329505083820642555140110802669417280047271073521902034892613836704611035935709522917416503201529607881752555 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991616269146200728800216611801810127154786923875939583363805473384872024513789137775055652502231066465498825685213756435722942522208572934826018659818328603753588 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412731234941101404944921415057286735598751533834754608191706076555894968957595202366608829373308066709416677670496300854621297134400773366760311827694929412487970664448286142577095835910144 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609250845853331860720581567860521618110735834371472259589597881444469377912314348012749304424693462091781531933248204739790571152550336708446718948563290509314250430570778299468543445592009405890561 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604121672216200807244397735162059303549782240704219678280941573709222310999446686796969566947861942527383069465115599603330519233925266145981725897948762472448 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604657984533398511128380696161973998968640591045736839148901163764524169521933285087621776811924646252669191487273304485299716587362327896765846276336504537088 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991628443435801116678383025016508190740795008428692022923642908982717161594994213919278047284283105556469108703169967516000633619212296016544041585057832865103872 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412748231356839883200926797122969376340902726747459017819013799634941232234309731571032186453764294705643969095616201282861266238109349159903099797080432346176126701359673948281490070568960 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609255408293949482915800209032127203229867573886344178263242729439162614582767038791751242970046692831998959612856194724542144602162985656541483592372993404805860714591881919095033611090303465291776 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +21430172143725344039741447416747135734328099194269775938858685112579378184657786065906763159178676625205218492566825428477050725853377832065983208189713200681844100397174224127137557678646374287640475087188412914436146644713764873912909317614682237526728015428718464118732506826116885039758058750738432 +235731893580978784437155921584218493077609091136967535327445536238373160031235646724974394750965442877257403418235079713247557984387156152725815290086845207500285104368916465398513134465110117164045225959072542058797613091851413613042002493761504612794008169715903105306057575087285735437338646258122752 +9740013239323168866062487850911573191252121083795613164211272383667327384926963766954623855846708526155771804871622157242819554900360224673989368122224649709898143630515684865784019964944777113732595927127133669611228650022406135193417284855873076955897883012352541941963924352470124250570037702210617344 +13582985265193575509847153720301345363547163848715837516812932466783689951768234614081082594902676106779962952908124868514580193484388163974010229906267257277629370088801142633029220476374120830201819937481485605394893790147430680868494971780019587951193256398520172478623000296862688521766032969946888901935204417993802764714508288 +3646154850295010964902624396817474390410105702108556391759286100433934630952342968680077393668206518645350322207926570056063791163256347839621106322437804761540352091937936756225487349008505906910901544548065233498934923554616145309059470154014938195304963669835205443004851378494121810273694832757966522610366086517324182782563251960938496 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824629198276151174244463087285660418287344529756165187857520911105123842660034918703411836307538943107430287596439419222071804002615797677806638572665083165692141839780886307603102541747070094713562715543794785904326970568977820621271154145831782622467599830140102357487631119091729219499088809459332415487 +736567904319114813700179347165898017864004333486947405305591758520610240861829766276798698618284354494716156033682943041579601713942220515540203161316998862077737405693327418524701312676891843887526247248550546356474902078886714910989494826726018489783987340302135409223113547673217455618750193884849347528160194394640717423882001111685525241940621668818619861722020482087095397955107969291288249444329152787862322599066175858052440630467418058473340907 +31847793196274107182845849867935019058119806419340392572260824606510195176311496560920629445019152089581060460884957727702584683631406487052881165260753593451678086770450460508976164978853315225613389231240714869753894387304963876717058650152672811697170570980613598309383691870969784601585900594981479511955574221514648792975451023932379869175500758313625655872192484128483431743888460039720362805862274612216016775291210943444487297807108709430373383284 +44462416394276340862910922260389321581298853470913371563358965890746390942505208917810214508921403677924050484037361854923909199530783769557857398908416797467991642660044081596444769282811977804250882370944636426195458324080999993435959869852668433762589077466327036503679884932798114847311436326315773506106222447586090692873957009455868034159802460539867856658115952688726716502746285402567852398888356313324109937916420499689593669109023205291494317874286388534278585340917710848 +11935289041890653422458560211344367565999989567726224393815132782921219808519438180124970259072038417888105302535754774032670805811336900569676094726678661851388189281957447472598923409448790006268973158495533882062541204142975446526119117611259327045262915006773486865554835011098276863061710309734987275751369401000805245194174420363093639844254247196438980433865369554332786383238465709007857728072714580953790040537248486657816917075965510971703569173409460696212044812838396933722603521 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046272 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046292 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957047179 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571754105966758923615108084021592063 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998595854119759254624519943537861725257726 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046292 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046712 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957065339 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571779458978716264538661165312507903 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132388005401501458178023893787435686497089486826 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957047179 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957065339 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957870735 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255572903865059024334498240320564625407 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132388307231960917050440985800712478475493047411 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571754105966758923615108084021592063 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571779458978716264538661165312507903 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255572903865059024334498240320564625407 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172976888286874738812007209510607836887249117247073360525221953535 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834198122532121152290057037619484503120616341536220725647709322168743493631 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998595854119759254624519943537861725257726 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132388005401501458178023893787435686497089486826 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132388307231960917050440985800712478475493047411 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834198122532121152290057037619484503120616341536220725647709322168743493631 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463854626286928489170704919821474820295850844991684637003273587403723479550263296 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463796730242309831072892700701204289449703517933314335935523147673822961969659903 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655464954651134682993025119737995967430683808765164544288322764969771673602221932543 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655516308442711432725606388842018712744416376479869592676696939779811349497410224127 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418968698206766676988716306797306798322733884687580499409184197685426822573709166274146087840056749258824482815 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230791227421993503490763661597227832901047900460489592404378000871316144391892888932790742958211751174484073818548600831 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463854626286928278546121583090225309497862411216895622648821577061255913565847551 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655466170468071670389962926268165408851695145524119751309302031986907765585741873151 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655568878051224983031298214051249798948144651581361401012371913663600469546748608511 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526419042090162341389109555755130857011166236435754198953444744823552445839967811195454110810091692840646745260031 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230810928425091629058572227350488203855814431230288513583376829012090818649816718005179773071922786029155937992071708671 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463970417934507959064766276062482280155927834544016458811138434453501800557314046 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655468602092670843680854464820582805235514519413989288868710685992144929212562669546 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655674016867227332942227595270059128305668055962387120247755620175759734935000185971 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526419188873513623781429523198315973233795834538066888757179285150590343875587544241222927524862886150078906499071 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230850330280999717900984674144544176694400193777498414739861975427990316393400034845574409410503472515333942385779408896 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988312365191525626829590504228669795829923743060941349315981180118158171906003267339308381977465988796174295002978654348297199013279790646750077514955096063 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988377833003683549666990768022606347812968075901862210611770825086271696916793837441522198067280137742930872414791776202806122512552382450373019214916091903 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060991281330472887427505692467283692428260984237396702409080041579422106531145355621474704941650537643531585080628703730450276879705291828941050483608186257407 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357569626768432140808575645041867964802739431380147844841991693339296041823615960460885574377967295802725391623284537619891699379074505410081618976696929783046658180816608368840237121535 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193136923234669388921625539957892128983675047329276337314997651683620870545893686589742398612991638706405781463837141767414520114039309101060121091306762606872851395428061281540895495284831813631 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060993337019774646966745702917403421794848327164932528377852825068090174463291770485332227948267459582315795169496460350884423131286503255930559257423443394558 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581061093895579249231687905351444692398327199439935205189809885492472498613816017905415292833090157145601654969236777907403461450700250245153410365797293170360298 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581065553667691947064071335763629958507536971291296797724320534291858012899109421989559045671132964720559347339120710084185252623383792198306639785840515561290867 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809363939133154801301027002810441006720532629601680079641441871666413942137974612480004014870562801430464267529001742230861455387809150874169137212974389956039478530383586623064319329304575 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987194846724589174059804584483304745511236739569637917361853588069843399469934785626256495648790733022348545220323284758961541307193328176980552320835887611653596765031114209324358525174267150073856 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581061001716899730860327787294516036840353702230284956824318991202480541082116487859573826725825287961689011509287552816105484327769184483035249934723314647826430 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581061269873058329712269778775015994188063131405455715404573791418133967674533135776273677288507587689842264965715961378250059448096107820519117250581008463429610 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581073162598692188795897100935189102558976315324278858438874180982363437048211470881912049743467580633439055758315881109361966034595157837928632708869729185430643 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809374561892991349244895987646743629051242993830435097325085051960084360405934477441677536970799479243839010777352698095857811302341003439862436501333952924874555567550900191628496417587199 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987197698249975187672471512160496190700192727823963719585278370577848353316503739461088579499762169689272944467670537846646968393786850876386949021665415182953273942957363202571157494643409987567616 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581061015124707660802924886868541034707739173689043494753349649171200634845421779793653366808184376110467613142567240273242354031620510169248595774949349344149503 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581061551437024858506808869829540949403158032039385011914217608761255936703944266391944019018048438814192899264589397978124323228973947230999379895327737086214143 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581085336888292576674063514149887166144984399877031297998711616580208574129416547026134444525519619724409338776272092189639657131598880919646655634109233446780927 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809391558308729827500901369712426269793394186743139506952392775039130623682649006646100894051255707240066302202472598524097780406049579233005224470719455858562711604462287997332890652246015 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987202260690592809867690153332101775819324467338835638258923218572541589986956430240090518045115400429490372147278527831398541843399499824481713665475118078444884226978466822197647660141704046968831 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824629198276151174244463087285660418287344529756165187857520911105123842660034918703411836307538943107430287596439419222071804002615797677806638572665083165692141839780886307603102541747070094713562715543794785904326970568977820621271154145831782622467599830140102357487631119091729219499088809459332415487 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824843499997588427684860501759827889644687810748107885616909497956249636441881496564070903939130729873682339781365087476356574509874331456127298404746980297698960280784858049844373917323856558456439120294666670033471332035424958270010283239007929444842867110294389542128818444159990388349486390046839799807 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864834347781343330617766485833689155244342862322740766531245793324803678590666777224684300553400226472956960854182818474553886146506790304524648561957579118102201358139311004818244759424154336225453007670995834731161023763072355512991590658521370041017185970985137026180965476310937373226864619089102792294399 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382945944971643394552440333018544909113467554612749139183355056603618393891608739152695663135014913939388630223870254054412894344624289470541920862626549594209167573670063373732089922672967834116510690953316456889794786342129422505749576092463192554010284300112795761408992790940526935790646439671993459275486838307032042854165296185343 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287321881537782656997343103601327303339215017873806116005292182631938677605782562544625650995475250258938656613604058187487401993335543020778644703484269290201404867303981882236730798076805901958398370897225037198612474339112946064484584134538861612429607839386002942061840246087892662062040346796957431605546122752671420426796831614652542615551 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +70149324220868077495255175920561715987048031760661657648151596049581927701126644407314161773169938523306300574636470765864723972756401953860971729649236966380158623144886433123904089438954731413136105939102963525135105941885179620757765851918707538235369974386271618715130954505741977781211162121976618183601835461375440982077945936461543052837790612502383395739504991310927477668395382345950562697672932264775996511143505676632322113137860859914092542 +771642566429548852447806935126178875857528349367278234129667556545401204712393088480455779504869323756369306321001178424511963700320421492470689026141606630181744854593750764362944983828502045544497165330132598776486165360736975828335424371105782920589069718248987805866440499563161755593322783341742800019620190075129850802857405301076973581215696737526217353134554904420202254352349205805456189674402254912535961622578562442955543244516469459055017962 +31882867858384541221593477455895299916113330435220723401084900404534986140162059883124286525905737058842713611172275963085517045617784688029811651125578201219782094219350883854814408650004925427270360149322296922173905650586814137634404579697052576127975653358560450706027018822859728901560473184438372964447034217195137926354426428121771317514775833382333253363605018550816538600285701276234530746092347714340690414314723330029390400421157760830955060339 +44462416394276340862910922260424396243409287509660999151319246748739914958385539746634290306946194641774613806241018935810494168792436919845175634291349159454369843636974567461269377050915985253151305716782880097347068525737970911517541922272679697044439338383672966048059649363603197225258288722959100457996166747560663282330850461947328029840291593918843260847507401028001791571453882893980386821221463169721351174430588439919666771233696844315006704459189491148327636741499387903 +11935289041890653422458560211344367566035064229836658432562760370881500666512962196005301087896114215912896266386318096236327886697921869831329245013996897234320551268335648449529409274273397774372980607395957227900784875294585648183090035692841379465274178288623747782900764555478041293866792687681839672394696352890749545168747009819987092335714242876928113812840773743724234722513540777715455219485249003286896896934489723171984857306038613096377208196921847281115147426887448334304280576 diff --git a/evm/src/cpu/kernel/tests/bignum/test_data/bignum_inputs b/evm/src/cpu/kernel/tests/bignum/test_data/bignum_inputs new file mode 100644 index 00000000..bd45bdf9 --- /dev/null +++ b/evm/src/cpu/kernel/tests/bignum/test_data/bignum_inputs @@ -0,0 +1,15 @@ +0 +1 +21 +908 +1267650597867046177654064545792 +340282366920938463463374607431768211455 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 diff --git a/evm/src/cpu/kernel/tests/bignum/test_data/cmp_outputs b/evm/src/cpu/kernel/tests/bignum/test_data/cmp_outputs new file mode 100644 index 00000000..e4e41124 --- /dev/null +++ b/evm/src/cpu/kernel/tests/bignum/test_data/cmp_outputs @@ -0,0 +1,225 @@ +0 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +1 +0 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +1 +1 +0 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +1 +1 +1 +0 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +1 +1 +1 +1 +0 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +1 +1 +1 +1 +1 +0 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +1 +1 +1 +1 +1 +1 +0 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +1 +1 +1 +1 +1 +1 +1 +0 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +1 +1 +1 +1 +1 +1 +1 +1 +0 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +1 +1 +1 +1 +1 +1 +1 +1 +1 +0 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +0 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +0 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +0 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +0 +115792089237316195423570985008687907853269984665640564039457584007913129639935 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +0 diff --git a/evm/src/cpu/kernel/tests/bignum/test_data/iszero_outputs b/evm/src/cpu/kernel/tests/bignum/test_data/iszero_outputs new file mode 100644 index 00000000..e32c9c6c --- /dev/null +++ b/evm/src/cpu/kernel/tests/bignum/test_data/iszero_outputs @@ -0,0 +1,15 @@ +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/evm/src/cpu/kernel/tests/bignum/test_data/mul_outputs b/evm/src/cpu/kernel/tests/bignum/test_data/mul_outputs new file mode 100644 index 00000000..b53c5f7e --- /dev/null +++ b/evm/src/cpu/kernel/tests/bignum/test_data/mul_outputs @@ -0,0 +1,225 @@ +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +21 +908 +1267650597867046177654064545792 +340282366920938463463374607431768211455 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +0 +21 +441 +19068 +26620662555207969730735355461632 +7145929705339707732730866756067132440555 +1215816936991820049838389159501298295810509592791450006603913202743172264886272 +2431633873979216987644919328942719307147268547998470985870930338835155784826880 +4863258473152507879183471746339103126521158417536030394524935575998782605623275 +68741202765818979270276983633379582196549482966904360579127216519201261330098607324506894304856394094406282403777947234369674236221393804088784959045632 +105586487448313957217630953653425358968668408786294503634300774628861320362441676458635398984170320306132770645519405205878947411928992353796866863213314027 +281563966528794539091054524955215094900633929296509267540226436097922037480312534843090816414714560916129249828990251803876343269504358060681650578506383339 +563127933057589078182109049910430189801267858593018911357569558066951448610928205184820357265838911550428123265590126067657221108914838323326397307129167872 +225016807509116112417285197875844925210445041539832647358016193682083470938906753692021013171376104564654794171951666999009032621460467236692823685991988607159363054170329353334944355625786930020224988415478335601579539769494531176085547834954163494030644162001543873246691321674227292917459616882753536 +736567904319114813700179347165898017864004333486947405305591758520610240861829766276798698618284354494716156033682943041579601713942220515540203161316988146991665543021307547800992939109024679837929112360581117013918612389794386017956541445146429151471384731055851996508875022310290766702717202280754490927819272344442130311818432332846202054796801431275025655264802408764738515518151514632480908325565788780147963367006809604639382187947539029097971691 +0 +908 +19068 +824464 +1151026742863277929309890607579136 +308976389164212124824744143548045536001140 +52569608513741552631107493182246612028378224297839838380778723242419067453177856 +105139217027291858322932702413332815756653325789648174055752607031539116791562240 +210278033029641769252313921222662173280057706815367409439459119190804505043139700 +2972238671969696817971976244719460030212710977807102828849881552354035489891882640507250477562362182748614496315732194705126866975667884481553178229211136 +4565358600146146340648043138919534568740519770378829014283100160143146613766525820211473441791745277998502654577696186997051630953882145583216910085604244596 +12174289600387878166413214698063586008084552752439543567929790665567295715815418173215545776407658157706921849748721363710462842319521767576139939299228384372 +24348579200775756332826429396127172016169105504879103405365388510704376920891562395610327828446749127989939805959801641401559846042603485599065178803489734656 +9729298153251306194042617127203199623384957034198478276241843041111037695834634873921670474267119187843169195625338744528581029537433535757956376518129793109557221580317097753720451186105453926588775689583539463154010576700049252756460830197065735837134519004638182709904558099057065808050158672835248128 +31847793196274107182845849867935019058119806419340392572260824606510195176311496560920629445019152089581060460884957727702584683631406487052881165260753582736592014907778440638252456605285448061563792096352745440411338097615871547824025696771093222358857968371367314896669453345606857912669867603377384655355233299464450205863387455153540545988356938076082061665735266055161074861451503585061555464743511248208302416059151577191074239364588830400998014068 +0 +1267650597867046177654064545792 +26620662555207969730735355461632 +1151026742863277929309890607579136 +1606938038272679619211255036084048932956190504430095264907264 +431359145870941220571487096504865044588697904564591140391738786447360 +73391955574979118963811141843059488536193514605218060347731553038824318137413435829926783487818828867436544 +146783911149691239803259475393272332038744581223672095908357420057841712239442615794649035123910216788213760 +293567262432083559770702660509494961636846893913475830448684457955877331972488384611363806317219648949452800 +4149515561151917970063980879655710938513649460124350952720371065270297197065154634382680097543307069927884450339928718724097725668943949230978441358030208342019760039438410280075264 +6373655901930312136397229380018411440828683949391920950832693445711366448193584697763678864931677968612065262908033170282412527802037703004824976134384286640214222530054133889372258304 +16996415738478256005382065682640742151192912704409604594012987116129634408058546371285779101609491343355313613863898166638327059654603396304113335697353121717251389843622698066460540928 +33992831476956512010764131365281484302385825408819231901736066162392911122587750794642859557837487570646738733764326406607430768230396539092082721200286809873288301231428402460695199744 +13582985265193575509847153720290630277475301176695966793104558898916525902171099726111653252346386417687634059875171486934990855171785554727726817192028731914702681172768151028934363876033198780003232825417916826555570603003610443324900765322801514628836373961563717819815659178099324514051673737887522648522145975473923735339139072 +44462416394276340862910922260389321581298853470913371563358965890746390942505208917810214508921403677924050484037361854923909199530783769557857398908416797467991642660044081596444758567725905941578862500220928052627591160031402858547990440510112144073496748573294083122100295594485512238065152913601534980743295758670057701269862152855527112109603873427804287879276629501582896265202691196110634325565999430887153483257613158570830305101308846059434951620873330091758706311542341632 +0 +340282366920938463463374607431768211455 +7145929705339707732730866756067132440555 +308976389164212124824744143548045536001140 +431359145870941220571487096504865044588697904564591140391738786447360 +115792089237316195423570985008687907852589419931798687112530834793049593217025 +19701003098197239571963727475337245584161626291901231402719522479678259504890677218990119895590117915143388591554560 +39402006196322807380529480735708200350692396090822410401547663254352517428719749608020233606624972587007562114662400 +78803862104411649792976274791681038936454943300723566886694079153850261012036590002656572187311458765011955822362625 +1113877103911668754551067286547922686738237475419584309931192581897577662915063323503306740447008536028968181678028580322422866333819711284625174374608617279642589745120484326564854874767360 +1710915231608582551713494414139930175751260546116444122900349352360496966554854730076753484481830650675467827629295222707109502155201699203484369755223655341193278275893163301956243837193027585 +4562440617622195218641171605585119131739514871918667547682857357314343535508689562160604455918497575074715174882382908134196095677901105600185199282794955018371204524886410100925712980030521345 +9124881235244390437282343211170238263479029743837341192530852050551013988199468564099149809149237792502394782872367659707645708326849200364829008985690446628655225628506036591091211274089922560 +3646154850295010964902624396817474390399390616036693719739415376725561063085178919082942505698777176089060633115597677023110409583667009527018497076154392047301826729011247840192495744913649306569979494349478121435366144715292958165239232610420731738086890347478323006048396719686780691510330825043607290550999833104265740262684222585569280 +11935289041890653422458560211344367565999989567726224393815132782921219808519438180124970259072038417888105302535754774032670805811336900569676094726678661851388189281957447472598923409448779291182901295823514011338832830575108282476521982723289897702706625317681157972521881629518687524749107700488703863037130875637878556278141428758998783243913325146240393321801800775493463196094645471464263521615496507631433158100292031999009575957202146963989209941350094442798986370318517904347234305 +0 +57896044618658097611351864738157061705262361561497619362091104892532012613632 +1215816936991820049838389159501298295810509592791450006603913202743172264886272 +52569608513741552631107493182246612028378224297839838380778723242419067453177856 +73391955574979118963811141843059488536193514605218060347731553038824318137413435829926783487818828867436544 +19701003098197239571963727475337245584161626291901231402719522479678259504890677218990119895590117915143388591554560 +3351951982485649263264086660821751293167574115217012473116062855570117177114956810549394311722122195190355926629690380263290286253266199596551551712231424 +6703903964959104207882943247098074879292236184530784614687051259089361504778664925296585557644723899819989557097938820112754998714546796218504411307048960 +13407782359700221432208153137018396716476230393601324554188676058418403973105159781474496977845448805812756231084668278028521746573850893544243696815308800 +189516368689051383356419666365934487249694726206307462692478442160356412055175068191548410359233923189538270288357620597887942150501998384340803566981539803652861191767034299241276777771401726930027167539955532412991464793964544 +291097142306427050053565423426590890568146840930776532405423684287884740444915857761347334012000265903675449121187612221625638517177392299309155307502337486020927127535947499456450345719682189031665783117734919052512795878316048384 +776259046150354466227894953415272126532120228827236797123305565388337686400499060284004070246335310139188795312112703394374362640691719752700909206017051198060493495608220461125520225112836119459965070690227765389768580522718527488 +1552518092300708932455789906830544253064240457654474631625503351024913201337446226079742769388732571127058525201398326436194714101150988019032351961389195980792206263906993685249030935631117974530339035198582125552984050009714458624 +620361101309323186180458062143306311203234091808422651940994483172973212453462540277947848500764537416293185308049243121091077089522237714087216426627812178598932718744797175293795424927554129248204812001597295596246882084347634304130710520242400817201806901439842621734294451519310289297352148130231477204202016235965703658712648032709044435339313088432114418262153009154752512 +2030684202530045702032438070068470600111523314891992114474287665026563901579442604747297208342924347358657516628421307413109601517971206668455722861607048951866317121347560401223028395731439655580245638497036905507303055096291514983167804903577061365248747133480848909746535730849828042674125732472216127172563383280944806187156793401092909358110607810689164992655422507992440651826516323860482006072417239646401793958680956430020069720523666773505207631846930990177373853120582291091033196123813538806140647566683428129469366272 +0 +115792089237105570840234253759177109864155645142784332660520492325483608801280 +2431633873979216987644919328942719307147268547998470985870930338835155784826880 +105139217027291858322932702413332815756653325789648174055752607031539116791562240 +146783911149691239803259475393272332038744581223672095908357420057841712239442615794649035123910216788213760 +39402006196322807380529480735708200350692396090822410401547663254352517428719749608020233606624972587007562114662400 +6703903964959104207882943247098074879292236184530784614687051259089361504778664925296585557644723899819989557097938820112754998714546796218504411307048960 +13407807929893819778475470707735784992488440665279129110225796518690280399801487040957178859490788616767266574533518552379422042573571257824675478529638400 +26815564719351665682859297115793503881598601899157213443769731667066042177950468012051000327834243644827516674656869253925854969676662574929007714762752000 +379032737377413310837469826127201516165849126556927185280268831441004642386080191344591587626743143491163530774059885949190517071683841202707214877193839283509836239507327810571115256102701286181423314856476535119531046873333760 +582194284611795095882563124181957331911668652816390808061798178917116866814434754607160150716463467811845369643570012125338680346889780167007790616300675328647243232411818768880659637664081627824716845155217383295556538120651407360 +1552518092297884921190276407777826343730130571016241164825192478707830380921635634356568453745503455149401263113730019700298099019902002012202155472213879518073654497303294521076488615535022163842239123103052036543841131161997803520 +3105036184595769842380552815555652687460261142032484404408169394138177593232526559709091771925126394796328107261127062087481484183515508524562872429687439110406240134689348936276584863546005281248676694097265868804492346319133736960 +1240722202616389513973922768685786106091078788555724681396110088894901580356174059693107801547999717844793849118253907517164294570375212313898259715085141105940658891307423763778538377665051892100124228941562467259128201610076266056373405707086736336167605239314782881108716366473706926696989024480092947548903006603393526774842227227605392632574744471346260936099413707173396480 +4061368405052703825017540452826323628177065892919822203995680056457293914967717151139514347845670761968317643193023213196105279034485542899856942497055973489887306964055240783810529148217259878326321073593635104947630604439996612121186052320432514468047976270758130684476727539892394554268861392044474193564110067997362607705131765085400073399409683739317269432145800594368855385753859106179981112207797478255195155380669937444019554506527587107321605367039934467094788088851405871320736566808054693946822238648612224007804026880 +0 +231583736816786089484927226016147767929578972263620494977377884571370600267775 +4863258473152507879183471746339103126521158417536030394524935575998782605623275 +210278033029641769252313921222662173280057706815367409439459119190804505043139700 +293567262432083559770702660509494961636846893913475830448684457955877331972488384611363806317219648949452800 +78803862104411649792976274791681038936454943300723566886694079153850261012036590002656572187311458765011955822362625 +13407782359700221432208153137018396716476230393601324554188676058418403973105159781474496977845448805812756231084668278028521746573850893544243696815308800 +26815564719351665682859297115793503881598601899157213443769731667066042177950468012051000327834243644827516674656869253925854969676662574929007714762752000 +53631027158026444898639041353951338860236953565976155186370673275827169990229796710610136585486710294744741538759339503142188427219888626557524901703450625 +758064029037559548223859302619650075474792064511873124215265408149659395559453789942397036648834306197292055977388138161024258210175532633810972040915105374809744387652086706188503922572983286780452241329985943497170267983052800 +1164386348601867966607659549490709240641434805493466720013626865708760416816760684474263347086593403580537140168446677038569831210140531685534851163995750025031331763664446019825967919583282914146489408839507982335431232969112551425 +3105030262937843909524927703451704725658035213057063685463909781308268889930827638236818973565112070382840731126979240983820442568989111483626724942061970361307566813811606244576718762256490550467423465073089242630619613999057076225 +6210060525875687819049855406903409451316070426114131520435474836896735901928651243521579858300210079569809751772692509393442960425269123499217289079803270033146012536744468900746753485654275750950451702497211174173610068660767948800 +2481439672835455316435450222961490952467054688477443973252759241836914049418059193066289201770080478782010589768308256548437208615056252516149995383823877308087652590010038324508787501850632011084265376115191445269164718609708653219057772287156297315205415965661016801043979428655461218374679406517792258741473669803979329510535342890018189384338466515427440201885258439091814400 +8122721319120455379930921158326117871838290539711891253924140849349950965031209192469013362813226005733220497444267273168824363782607514900842646678617218420603025285381689301022402706647780653422402593097268270904777394649862358017106423565800216445602438232961812733726274533361295534877361561034733716956723820342508274535124544488827440330912196294237990424996646092080259959888790753448676537815274083485701600749922454909872662388097681488248458568576219237116237159724865297204930388201921385039717285631411970780665217025 +0 +3273390607896141870013189696827599152216642046043064789482248405676250539528505110690804490707447337828870590656092725446174963629590181147084998049792 +68741202765818979270276983633379582196549482966904360579127216519201261330098607324506894304856394094406282403777947234369674236221393804088784959045632 +2972238671969696817971976244719460030212710977807102828849881552354035489891882640507250477562362182748614496315732194705126866975667884481553178229211136 +4149515561151917970063980879655710938513649460124350952720371065270297197065154634382680097543307069927884450339928718724097725668943949230978441358030208342019760039438410280075264 +1113877103911668754551067286547922686738237475419584309931192581897577662915063323503306740447008536028968181678028580322422866333819711284625174374608617279642589745120484326564854874767360 +189516368689051383356419666365934487249694726206307462692478442160356412055175068191548410359233923189538270288357620597887942150501998384340803566981539803652861191767034299241276777771401726930027167539955532412991464793964544 +379032737377413310837469826127201516165849126556927185280268831441004642386080191344591587626743143491163530774059885949190517071683841202707214877193839283509836239507327810571115256102701286181423314856476535119531046873333760 +758064029037559548223859302619650075474792064511873124215265408149659395559453789942397036648834306197292055977388138161024258210175532633810972040915105374809744387652086706188503922572983286780452241329985943497170267983052800 +10715086071862673209484250490600018105614048117055336074430675836924241540472703456698285220172692381666915465456597657220856438022326048260043738079097569861723477222864084024723456654120868104119493560585512807944190828392178187984719137393049169103254142087127248661337626132381236011316443311243264 +16458372206383560850154727152772241309834362634645429482097685030171884111143709030259566480970840675586286057165552281949963074948236086284290260005656649082848245798566424861913543183906541851941660459520122404258933779435071795354694349641611033685309336221143617936715894403545863381859480370679906304 +43888992550349509466047490008389760228034918444740354476264789433451422494435484145605446873947256471512988292597450618642207676514741311261882165968599848430310026415377131508214755446432997138431116604680521746555008944242629428478468183278110882114932777127534190355484669739785885245968619478007676928 +87777985100699018932094980016779520456069836889480767605004803903623391638540464457280122746011077411993751425324753978750781979522477580196467009117071428016628499217023421730630965195213525748235513398478599337876370083082111993797578339643292113170849335330813036879783075982297998725326138636180127744 +35074662110434034853557842365135370752418744845644232722536724705537763948482350096800897815346751615649214933728622564185847196492435060706089044924648133026630781093917108095545664072447733261889308217617387286462129653489067160073127037621299577013488448084508231783465815261392679840044175715075506479855049458960417568692240224459402814116944692003822183536118940032489278563958573604110859792014017609258239480765944544557609136035015279952003072 +114813069527425452423283320117768198402231770208869520047727692128105340272556505252150160006414760200146251310083289009338166699942758143608103582817139261613860686884404865091240091700335916571366968398775231636972558602982410372368561085607640039695044427708003371630792169233277670446637805866344012196830083200549854376617192853167566486801110672010487276196765581360935421367998631422802129683085092788505721142860577202194007940588172852101767238437699363756153062785321947495141655278338111834268668260296874876439322420209270108736741859953710415066991479177424624334867465316525824363705925632 +0 +5027927973729236057982426364448826617555638513633071601633370220421967636306746498030257094484300966958703364072352628851378448187094873990326993486348287 +105586487448313957217630953653425358968668408786294503634300774628861320362441676458635398984170320306132770645519405205878947411928992353796866863213314027 +4565358600146146340648043138919534568740519770378829014283100160143146613766525820211473441791745277998502654577696186997051630953882145583216910085604244596 +6373655901930312136397229380018411440828683949391920950832693445711366448193584697763678864931677968612065262908033170282412527802037703004824976134384286640214222530054133889372258304 +1710915231608582551713494414139930175751260546116444122900349352360496966554854730076753484481830650675467827629295222707109502155201699203484369755223655341193278275893163301956243837193027585 +291097142306427050053565423426590890568146840930776532405423684287884740444915857761347334012000265903675449121187612221625638517177392299309155307502337486020927127535947499456450345719682189031665783117734919052512795878316048384 +582194284611795095882563124181957331911668652816390808061798178917116866814434754607160150716463467811845369643570012125338680346889780167007790616300675328647243232411818768880659637664081627824716845155217383295556538120651407360 +1164386348601867966607659549490709240641434805493466720013626865708760416816760684474263347086593403580537140168446677038569831210140531685534851163995750025031331763664446019825967919583282914146489408839507982335431232969112551425 +16458372206383560850154727152772241309834362634645429482097685030171884111143709030259566480970840675586286057165552281949963074948236086284290260005656649082848245798566424861913543183906541851941660459520122404258933779435071795354694349641611033685309336221143617936715894403545863381859480370679906304 +25280059709008981479231968148711644861442111696433705443231567360117402528393306066518309787037990431336656280044426224316649696164180810324022564882675140987960579876942528723700768267175237032707899300231700312150169638715161500573218061631068318350665689512114702779435677385026007774824467356638267834369 +67413492557347065242233762416053344604668789415978336070232719704519730695842285928289497175591340668357371303688672579355774019833840277487199698360245654983419254719431470785652320406511710713843764264258846732773932462012692405900266395961054012873582577495350462230973011642886763600990552681342023237633 +134826985114694130484467524832106689209337578831956762230667385079098314604114856488714967534864721366751145206577896381937685648970101488283024945486839684466321300593943839555804243973666843820217508302523380061872683673515732869098988513858354359158586336115486301550288354364817320561524260650122775363584 +53874681001634843991219960220676811838216618976411872431379454389487697453585414607630678378827390586054634875212617995067952662788488677051131226188233783645486119633174249397007355413950452332486425618874867205381482252662669001815967811090854730467120253594575199233845159152018106715728564966104973555959854476034899985603379172050429045260764066870120309159237337727562784303384359771520036909014223788365313020881488428759631128761329980986194132992 +176352874794152226923041126648344020296255845787663270025002097998433518218912651792864315498223942025499431461820100039971032945845086214853910514425858431681855101933052310870599356102672426974402827054711569107570218750844042593899023102723914290002809698086928282996956938154665332804357164535720651529889760012561396833002255365927318549914998445177047355818945707770980966071916771923738923854573521041830764111506524804411686150461839884079980325493144566147614078318969489021758698999020279168507320287970878237811504779638217033120905407240942949803405092731964364881039731836747753076040480587777 +0 +13407807929942597099574024997867385471458758537929012740010782671329620832395834992528134114986407662672821420428107228756016346166874193365792884690780159 +281563966528794539091054524955215094900633929296509267540226436097922037480312534843090816414714560916129249828990251803876343269504358060681650578506383339 +12174289600387878166413214698063586008084552752439543567929790665567295715815418173215545776407658157706921849748721363710462842319521767576139939299228384372 +16996415738478256005382065682640742151192912704409604594012987116129634408058546371285779101609491343355313613863898166638327059654603396304113335697353121717251389843622698066460540928 +4562440617622195218641171605585119131739514871918667547682857357314343535508689562160604455918497575074715174882382908134196095677901105600185199282794955018371204524886410100925712980030521345 +776259046150354466227894953415272126532120228827236797123305565388337686400499060284004070246335310139188795312112703394374362640691719752700909206017051198060493495608220461125520225112836119459965070690227765389768580522718527488 +1552518092297884921190276407777826343730130571016241164825192478707830380921635634356568453745503455149401263113730019700298099019902002012202155472213879518073654497303294521076488615535022163842239123103052036543841131161997803520 +3105030262937843909524927703451704725658035213057063685463909781308268889930827638236818973565112070382840731126979240983820442568989111483626724942061970361307566813811606244576718762256490550467423465073089242630619613999057076225 +43888992550349509466047490008389760228034918444740354476264789433451422494435484145605446873947256471512988292597450618642207676514741311261882165968599848430310026415377131508214755446432997138431116604680521746555008944242629428478468183278110882114932777127534190355484669739785885245968619478007676928 +67413492557347065242233762416053344604668789415978336070232719704519730695842285928289497175591340668357371303688672579355774019833840277487199698360245654983419254719431470785652320406511710713843764264258846732773932462012692405900266395961054012873582577495350462230973011642886763600990552681342023237633 +179769313486231590772930519069826442426264354005082326596360185112449176958549873259557850386600277367825925997915804457268344327753240407083712876794615624877762257166854166161646934596377646965522119647578649647126703396773127858133295428017635762092566594653974618708449402594449637475763618354340068065281 +359538626972463181545861038139652884852528708010164893433258891975305712994145996750811464699841724874842731010897931000393441458205293971046234853904111613343804779646728343027691647116232436982584254759296818415737834043273351893507362234301351226814369365796651940053069649153544102516262530232441150373888 +143665816004337806760172922323967843540707266966555160070938769845933482343514311921981576218185379382379331497993348644831971734671586556667433058226409769129546130073493215528938527708576559133205415270644020134698724204081225254029881946465693095984137609224865240709292656860316268992459694963883823498044606777540574301742157684362334319609311262061951308672635789253885343679712825576151996358495453517343899352653487644349083554108658142161712185344 +470274332784334653125768479190507147507942688099845821153656843754997301836979240962837606053917822376117946484914782536168160296609184534239096896145262203039351588043847354547077881392556187451052716096931348618124350989790368724551688012179157579351487604719105146798178247445433672967393357192101321816498019101823012168469706240238546733430563115610529101897377344839733586268940478469960836347004487048570855680122137578043206023975369775048480356517721340390187833972378623137126307547351741242129046523455257536374422351385724837117101473491922399552018441281779378146120832426011456202350251737089 +0 +26815615859885194199148049995734770942917517075858043397979502765092926124329914532610493203135186264306101107885244098459867671853087539206018919387103232 +563127933057589078182109049910430189801267858593018911357569558066951448610928205184820357265838911550428123265590126067657221108914838323326397307129167872 +24348579200775756332826429396127172016169105504879103405365388510704376920891562395610327828446749127989939805959801641401559846042603485599065178803489734656 +33992831476956512010764131365281484302385825408819231901736066162392911122587750794642859557837487570646738733764326406607430768230396539092082721200286809873288301231428402460695199744 +9124881235244390437282343211170238263479029743837341192530852050551013988199468564099149809149237792502394782872367659707645708326849200364829008985690446628655225628506036591091211274089922560 +1552518092300708932455789906830544253064240457654474631625503351024913201337446226079742769388732571127058525201398326436194714101150988019032351961389195980792206263906993685249030935631117974530339035198582125552984050009714458624 +3105036184595769842380552815555652687460261142032484404408169394138177593232526559709091771925126394796328107261127062087481484183515508524562872429687439110406240134689348936276584863546005281248676694097265868804492346319133736960 +6210060525875687819049855406903409451316070426114131520435474836896735901928651243521579858300210079569809751772692509393442960425269123499217289079803270033146012536744468900746753485654275750950451702497211174173610068660767948800 +87777985100699018932094980016779520456069836889480767605004803903623391638540464457280122746011077411993751425324753978750781979522477580196467009117071428016628499217023421730630965195213525748235513398478599337876370083082111993797578339643292113170849335330813036879783075982297998725326138636180127744 +134826985114694130484467524832106689209337578831956762230667385079098314604114856488714967534864721366751145206577896381937685648970101488283024945486839684466321300593943839555804243973666843820217508302523380061872683673515732869098988513858354359158586336115486301550288354364817320561524260650122775363584 +359538626972463181545861038139652884852528708010164893433258891975305712994145996750811464699841724874842731010897931000393441458205293971046234853904111613343804779646728343027691647116232436982584254759296818415737834043273351893507362234301351226814369365796651940053069649153544102516262530232441150373888 +719077253944926363091722076279305769705057416020330267347594827451426144142384493965014457252965790028388273268575745766448202845714472108972056832957787126548989380860079998712572623109761917189596553766242330909605534894906264486337757228291297942005327959842043718998160370035708197081835945941328224845824 +287331632008675613520345844647935687081414533933110512134339071188196745795513335307638657529820500030503638059893998544639282004826074078543526937501430385498822553680856810441605837007924382387640823649251663812111395581050675179334316291609265083908971530669507424781643811407050868800014638372550585796767486279157989351235817419037012278476998673070763482207177579797214780269850906321355704457864297379025560392407254253435440813631626425868706906112 +940548665568669306251536958381014295015885376199692270773634051571468443177252576492255360423853770864325258737964248491672738005473375204458692172487804734089712687353813343670064744128701098573532877590228667667008286737596697852387981631862326481177071413971930746756905828624662822957794948866823607625220615269013165228239618537011536940291208905424160713389821033135818514340985521905976691408942139437741483410228329038000371498590009406379772049151623867582176028814687068466685902099735918960489164147117893952824903803155286426295341357243145288763878804327513759861599032840758403923281677647872 +0 +10715086071862672019870723708373567867164049597134887969429342556289689092328893032953381579589338312602609246283412714238525362926688916032991604094856600340922050198587112063568778839323187143820237543594206457218073322356882436956454658807341118763364007714359232059366253413058442519879029375369216 +225016807509116112417285197875844925210445041539832647358016193682083470938906753692021013171376104564654794171951666999009032621460467236692823685991988607159363054170329353334944355625786930020224988415478335601579539769494531176085547834954163494030644162001543873246691321674227292917459616882753536 +9729298153251306194042617127203199623384957034198478276241843041111037695834634873921670474267119187843169195625338744528581029537433535757956376518129793109557221580317097753720451186105453926588775689583539463154010576700049252756460830197065735837134519004638182709904558099057065808050158672835248128 +13582985265193575509847153720290630277475301176695966793104558898916525902171099726111653252346386417687634059875171486934990855171785554727726817192028731914702681172768151028934363876033198780003232825417916826555570603003610443324900765322801514628836373961563717819815659178099324514051673737887522648522145975473923735339139072 +3646154850295010964902624396817474390399390616036693719739415376725561063085178919082942505698777176089060633115597677023110409583667009527018497076154392047301826729011247840192495744913649306569979494349478121435366144715292958165239232610420731738086890347478323006048396719686780691510330825043607290550999833104265740262684222585569280 +620361101309323186180458062143306311203234091808422651940994483172973212453462540277947848500764537416293185308049243121091077089522237714087216426627812178598932718744797175293795424927554129248204812001597295596246882084347634304130710520242400817201806901439842621734294451519310289297352148130231477204202016235965703658712648032709044435339313088432114418262153009154752512 +1240722202616389513973922768685786106091078788555724681396110088894901580356174059693107801547999717844793849118253907517164294570375212313898259715085141105940658891307423763778538377665051892100124228941562467259128201610076266056373405707086736336167605239314782881108716366473706926696989024480092947548903006603393526774842227227605392632574744471346260936099413707173396480 +2481439672835455316435450222961490952467054688477443973252759241836914049418059193066289201770080478782010589768308256548437208615056252516149995383823877308087652590010038324508787501850632011084265376115191445269164718609708653219057772287156297315205415965661016801043979428655461218374679406517792258741473669803979329510535342890018189384338466515427440201885258439091814400 +35074662110434034853557842365135370752418744845644232722536724705537763948482350096800897815346751615649214933728622564185847196492435060706089044924648133026630781093917108095545664072447733261889308217617387286462129653489067160073127037621299577013488448084508231783465815261392679840044175715075506479855049458960417568692240224459402814116944692003822183536118940032489278563958573604110859792014017609258239480765944544557609136035015279952003072 +53874681001634843991219960220676811838216618976411872431379454389487697453585414607630678378827390586054634875212617995067952662788488677051131226188233783645486119633174249397007355413950452332486425618874867205381482252662669001815967811090854730467120253594575199233845159152018106715728564966104973555959854476034899985603379172050429045260764066870120309159237337727562784303384359771520036909014223788365313020881488428759631128761329980986194132992 +143665816004337806760172922323967843540707266966555160070938769845933482343514311921981576218185379382379331497993348644831971734671586556667433058226409769129546130073493215528938527708576559133205415270644020134698724204081225254029881946465693095984137609224865240709292656860316268992459694963883823498044606777540574301742157684362334319609311262061951308672635789253885343679712825576151996358495453517343899352653487644349083554108658142161712185344 +287331632008675613520345844647935687081414533933110512134339071188196745795513335307638657529820500030503638059893998544639282004826074078543526937501430385498822553680856810441605837007924382387640823649251663812111395581050675179334316291609265083908971530669507424781643811407050868800014638372550585796767486279157989351235817419037012278476998673070763482207177579797214780269850906321355704457864297379025560392407254253435440813631626425868706906112 +114813069527425426929660656670434000556791117993150086180221643697431093173028910532415727113435976215204539871783667883838967071195340228232917109351973450013767101034272479645738741907650504496198421145870980109769343781666731468018474148841379223523433938268079692841589810552977465445261846437407748635458762124821556936873529967035483590621122322119705006554547460062408802518269990075352861435909928146945580063563725505925881145977291236879775785378910221502159993605883245075109657690762294065063726665915384443183063224455834919138638489409150864878627937633765733984255718952202044576320454656 +375828023454801161958069925084019843923978286415518836749560060086790811063826786575473978319828101315166509670501153778395493519601305062611233710167108096659872687219140685926605165995932330503576533938874126310080807833945025154398047371417183906188778761688181994841114264769649793185124682348180893134333861320517448227288705530984286877458322203246948912271425933606164725949285658013879720265044644617847420446340162585011712000860105735035610334678196167563897824599954042423669530327316471628496333180947012248953569457951187522058076800530227428892238847959130402967459985851634689104636645635632818315245484817355205865998912643567216769076790812429039605288671959330499956935814269560500882854907846825228822521982049802574527070231420993536 +0 +35074662110434038747627587960280857993524015880330828824075798024790963850563322203657080886584969261653150287318235382932361986378200976930485864824618483190079311572443216561952044719477365706568052969551481762567552970942589810378882925959353769117684987193135809357565477252870988890605581060988309091800917730687720491038972968230771526418895306251191697869752495655463738834197691172975281348836466132387998255571752838316161056568930429957046271 +736567904319114813700179347165898017864004333486947405305591758520610240861829766276798698618284354494716156033682943041579601713942220515540203161316988146991665543021307547800992939109024679837929112360581117013918612389794386017956541445146429151471384731055851996508875022310290766702717202280754490927819272344442130311818432332846202054796801431275025655264802408764738515518151514632480908325565788780147963367006809604639382187947539029097971691 +31847793196274107182845849867935019058119806419340392572260824606510195176311496560920629445019152089581060460884957727702584683631406487052881165260753582736592014907778440638252456605285448061563792096352745440411338097615871547824025696771093222358857968371367314896669453345606857912669867603377384655355233299464450205863387455153540545988356938076082061665735266055161074861451503585061555464743511248208302416059151577191074239364588830400998014068 +44462416394276340862910922260389321581298853470913371563358965890746390942505208917810214508921403677924050484037361854923909199530783769557857398908416797467991642660044081596444758567725905941578862500220928052627591160031402858547990440510112144073496748573294083122100295594485512238065152913601534980743295758670057701269862152855527112109603873427804287879276629501582896265202691196110634325565999430887153483257613158570830305101308846059434951620873330091758706311542341632 +11935289041890653422458560211344367565999989567726224393815132782921219808519438180124970259072038417888105302535754774032670805811336900569676094726678661851388189281957447472598923409448779291182901295823514011338832830575108282476521982723289897702706625317681157972521881629518687524749107700488703863037130875637878556278141428758998783243913325146240393321801800775493463196094645471464263521615496507631433158100292031999009575957202146963989209941350094442798986370318517904347234305 +2030684202530045702032438070068470600111523314891992114474287665026563901579442604747297208342924347358657516628421307413109601517971206668455722861607048951866317121347560401223028395731439655580245638497036905507303055096291514983167804903577061365248747133480848909746535730849828042674125732472216127172563383280944806187156793401092909358110607810689164992655422507992440651826516323860482006072417239646401793958680956430020069720523666773505207631846930990177373853120582291091033196123813538806140647566683428129469366272 +4061368405052703825017540452826323628177065892919822203995680056457293914967717151139514347845670761968317643193023213196105279034485542899856942497055973489887306964055240783810529148217259878326321073593635104947630604439996612121186052320432514468047976270758130684476727539892394554268861392044474193564110067997362607705131765085400073399409683739317269432145800594368855385753859106179981112207797478255195155380669937444019554506527587107321605367039934467094788088851405871320736566808054693946822238648612224007804026880 +8122721319120455379930921158326117871838290539711891253924140849349950965031209192469013362813226005733220497444267273168824363782607514900842646678617218420603025285381689301022402706647780653422402593097268270904777394649862358017106423565800216445602438232961812733726274533361295534877361561034733716956723820342508274535124544488827440330912196294237990424996646092080259959888790753448676537815274083485701600749922454909872662388097681488248458568576219237116237159724865297204930388201921385039717285631411970780665217025 +114813069527425452423283320117768198402231770208869520047727692128105340272556505252150160006414760200146251310083289009338166699942758143608103582817139261613860686884404865091240091700335916571366968398775231636972558602982410372368561085607640039695044427708003371630792169233277670446637805866344012196830083200549854376617192853167566486801110672010487276196765581360935421367998631422802129683085092788505721142860577202194007940588172852101767238437699363756153062785321947495141655278338111834268668260296874876439322420209270108736741859953710415066991479177424624334867465316525824363705925632 +176352874794152226923041126648344020296255845787663270025002097998433518218912651792864315498223942025499431461820100039971032945845086214853910514425858431681855101933052310870599356102672426974402827054711569107570218750844042593899023102723914290002809698086928282996956938154665332804357164535720651529889760012561396833002255365927318549914998445177047355818945707770980966071916771923738923854573521041830764111506524804411686150461839884079980325493144566147614078318969489021758698999020279168507320287970878237811504779638217033120905407240942949803405092731964364881039731836747753076040480587777 +470274332784334653125768479190507147507942688099845821153656843754997301836979240962837606053917822376117946484914782536168160296609184534239096896145262203039351588043847354547077881392556187451052716096931348618124350989790368724551688012179157579351487604719105146798178247445433672967393357192101321816498019101823012168469706240238546733430563115610529101897377344839733586268940478469960836347004487048570855680122137578043206023975369775048480356517721340390187833972378623137126307547351741242129046523455257536374422351385724837117101473491922399552018441281779378146120832426011456202350251737089 +940548665568669306251536958381014295015885376199692270773634051571468443177252576492255360423853770864325258737964248491672738005473375204458692172487804734089712687353813343670064744128701098573532877590228667667008286737596697852387981631862326481177071413971930746756905828624662822957794948866823607625220615269013165228239618537011536940291208905424160713389821033135818514340985521905976691408942139437741483410228329038000371498590009406379772049151623867582176028814687068466685902099735918960489164147117893952824903803155286426295341357243145288763878804327513759861599032840758403923281677647872 +375828023454801161958069925084019843923978286415518836749560060086790811063826786575473978319828101315166509670501153778395493519601305062611233710167108096659872687219140685926605165995932330503576533938874126310080807833945025154398047371417183906188778761688181994841114264769649793185124682348180893134333861320517448227288705530984286877458322203246948912271425933606164725949285658013879720265044644617847420446340162585011712000860105735035610334678196167563897824599954042423669530327316471628496333180947012248953569457951187522058076800530227428892238847959130402967459985851634689104636645635632818315245484817355205865998912643567216769076790812429039605288671959330499956935814269560500882854907846825228822521982049802574527070231420993536 +1230231922161117176931558813276752514640713895736833715766118029160058800614672948775360067838593459582429640872806815375600524611787633664372109038831131496892713847574204213375769343685580784773753635629758429922695406379579200240048301333922009856375733053746023334939149959900017297080529761791881121040475796858581600002403295404329868081465157652227751491087455277833629681152969524186808613504119583496193428420962898057357571055319374451607243028930569896539578660288198289657864101794216603970753824498208473733314597712660353208543367490975176753797670373382265859509054611517991409426349053031299407068631581080918639237312826090371923206219034977458927000306459751555164292071452400788382130601457910261333218639691866553206384714007138038691594287732934081410852761487999922797074320518605005374647219205312884015226747835223983423030251792941745800299484458323597491553884981698082835005441 diff --git a/evm/src/cpu/kernel/tests/bignum/test_data/shr_outputs b/evm/src/cpu/kernel/tests/bignum/test_data/shr_outputs new file mode 100644 index 00000000..e332af07 --- /dev/null +++ b/evm/src/cpu/kernel/tests/bignum/test_data/shr_outputs @@ -0,0 +1,15 @@ +0 +0 +10 +454 +633825298933523088827032272896 +170141183460469231731687303715884105727 +28948022309329048805675932369078530852631180780748809681045552446266006306816 +57896044618552785420117126879588554932077822571392166330260246162741804400640 +115791868408393044742463613008073883964789486131810247488688942285685300133887 +1636695303948070935006594848413799576108321023021532394741124202838125269764252555345402245353723668914435295328046362723087481814795090573542499024896 +2513963986864618028991213182224413308777819256816535800816685110210983818153373249015128547242150483479351682036176314425689224093547436995163496743174143 +6703903964971298549787012498933692735729379268964506370005391335664810416197917496264067057493203831336410710214053614378008173083437096682896442345390079 +13407807929942597099574024997867385471458758537929021698989751382546463062164957266305246601567593132153050553942622049229933835926543769603009459693551616 +5357543035931336009935361854186783933582024798567443984714671278144844546164446516476690789794669156301304623141706357119262681463344458016495802047428300170461025099293556031784389419661593571910118771797103228609036661178441218478227329403670559381682003857179616029683126706529221259939514687684608 +17537331055217019373813793980140428996762007940165414412037899012395481925281661101828540443292484630826575143659117691466180993189100488465242932412309241595039655786221608280976022359738682853284026484775740881283776485471294905189441462979676884558842493596567904678782738626435494445302790530494154545900458865343860245519486484115385763209447653125595848934876247827731869417098845586487640674418233066193999127785876419158080528284465214978523135 diff --git a/evm/src/cpu/kernel/tests/bignum/test_data/u128_inputs b/evm/src/cpu/kernel/tests/bignum/test_data/u128_inputs new file mode 100644 index 00000000..ca67d6e7 --- /dev/null +++ b/evm/src/cpu/kernel/tests/bignum/test_data/u128_inputs @@ -0,0 +1,6 @@ +0 +1 +21 +908 +1267650597867046177654064545792 +340282366920938463463374607431768211455 From fda64475bb3136b1c073c97ddca1f8dd25aebe61 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 16 Mar 2023 11:20:59 -0700 Subject: [PATCH 46/62] fmt --- evm/src/cpu/kernel/tests/bignum/mod.rs | 95 ++++++++++++++++++-------- 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum/mod.rs b/evm/src/cpu/kernel/tests/bignum/mod.rs index 687347a5..b504c9b0 100644 --- a/evm/src/cpu/kernel/tests/bignum/mod.rs +++ b/evm/src/cpu/kernel/tests/bignum/mod.rs @@ -1,5 +1,5 @@ use std::fs::File; -use std::io::{BufReader, BufRead}; +use std::io::{BufRead, BufReader}; use std::path::PathBuf; use anyhow::Result; @@ -38,19 +38,25 @@ fn full_path(filename: &str) -> PathBuf { fn test_data(filename: &str) -> Vec { let file = File::open(full_path(filename)).unwrap(); let lines = BufReader::new(file).lines(); - lines.map(|line| BigUint::parse_bytes(&line.unwrap().as_bytes(), 10).unwrap()).collect() + lines + .map(|line| BigUint::parse_bytes(&line.unwrap().as_bytes(), 10).unwrap()) + .collect() } fn test_data_u128(filename: &str) -> Vec { let file = File::open(full_path(filename)).unwrap(); let lines = BufReader::new(file).lines(); - lines.map(|line| line.unwrap().parse::().unwrap()).collect() + lines + .map(|line| line.unwrap().parse::().unwrap()) + .collect() } fn test_data_u256(filename: &str) -> Vec { let file = File::open(full_path(filename)).unwrap(); let lines = BufReader::new(file).lines(); - lines.map(|line| U256::from_dec_str(&line.unwrap()).unwrap()).collect() + lines + .map(|line| U256::from_dec_str(&line.unwrap()).unwrap()) + .collect() } // Convert each biguint to a vector of bignum limbs, pad to the given length, and concatenate. @@ -95,27 +101,33 @@ fn run_test(fn_label: &str, memory: Vec, stack: Vec) -> Result<(Vec< Ok((new_memory, interpreter.stack().to_vec())) } -fn test_shr_bignum(input: BigUint, expected_output: BigUint) -> Result<()> -{ +fn test_shr_bignum(input: BigUint, expected_output: BigUint) -> Result<()> { let len = bignum_len(&input); let memory = biguint_to_mem_vec(input.clone()); - - let input_start_loc = 0; - let (new_memory, _new_stack) = run_test("shr_bignum", memory, vec![len.into(), input_start_loc.into()])?; - let output = mem_vec_to_biguint(&new_memory[input_start_loc..input_start_loc+len]); + let input_start_loc = 0; + let (new_memory, _new_stack) = run_test( + "shr_bignum", + memory, + vec![len.into(), input_start_loc.into()], + )?; + + let output = mem_vec_to_biguint(&new_memory[input_start_loc..input_start_loc + len]); assert_eq!(output, expected_output); Ok(()) } -fn test_iszero_bignum(input: BigUint, expected_output: U256) -> Result<()> -{ +fn test_iszero_bignum(input: BigUint, expected_output: U256) -> Result<()> { let len = bignum_len(&input); let memory = biguint_to_mem_vec(input.clone()); - + let input_start_loc = 0; - let (_new_memory, new_stack) = run_test("iszero_bignum", memory, vec![len.into(), input_start_loc.into()])?; + let (_new_memory, new_stack) = run_test( + "iszero_bignum", + memory, + vec![len.into(), input_start_loc.into()], + )?; let output = new_stack[0]; assert_eq!(output, expected_output); @@ -123,14 +135,17 @@ fn test_iszero_bignum(input: BigUint, expected_output: U256) -> Result<()> Ok(()) } -fn test_cmp_bignum(a: BigUint, b: BigUint, expected_output: U256) -> Result<()> -{ +fn test_cmp_bignum(a: BigUint, b: BigUint, expected_output: U256) -> Result<()> { let len = bignum_len(&a).max(bignum_len(&b)); let memory = pad_bignums(&[a.clone(), b.clone()], len); let a_start_loc = 0; let b_start_loc = len; - let (_new_memory, new_stack) = run_test("cmp_bignum", memory, vec![len.into(), a_start_loc.into(), b_start_loc.into()])?; + let (_new_memory, new_stack) = run_test( + "cmp_bignum", + memory, + vec![len.into(), a_start_loc.into(), b_start_loc.into()], + )?; let output = new_stack[0]; assert_eq!(output, expected_output); @@ -138,49 +153,54 @@ fn test_cmp_bignum(a: BigUint, b: BigUint, expected_output: U256) -> Result<()> Ok(()) } -fn test_add_bignum(a: BigUint, b: BigUint, expected_output: BigUint) -> Result<()> -{ +fn test_add_bignum(a: BigUint, b: BigUint, expected_output: BigUint) -> Result<()> { let len = bignum_len(&a).max(bignum_len(&b)); let memory = pad_bignums(&[a.clone(), b.clone()], len); let a_start_loc = 0; let b_start_loc = len; - let (mut new_memory, new_stack) = run_test("add_bignum", memory, vec![len.into(), a_start_loc.into(), b_start_loc.into()])?; + let (mut new_memory, new_stack) = run_test( + "add_bignum", + memory, + vec![len.into(), a_start_loc.into(), b_start_loc.into()], + )?; // Determine actual sum, appending the final carry if nonzero. let carry_limb = new_stack[0]; if carry_limb > 0.into() { new_memory[len] = carry_limb; } - let output = mem_vec_to_biguint(&new_memory[a_start_loc..a_start_loc+len]); + let output = mem_vec_to_biguint(&new_memory[a_start_loc..a_start_loc + len]); assert_eq!(output, expected_output); Ok(()) } -fn test_addmul_bignum(a: BigUint, b: BigUint, c: u128, expected_output: BigUint) -> Result<()> -{ +fn test_addmul_bignum(a: BigUint, b: BigUint, c: u128, expected_output: BigUint) -> Result<()> { let len = bignum_len(&a).max(bignum_len(&b)); let mut memory = pad_bignums(&[a.clone(), b.clone()], len); memory.splice(len..len, vec![0.into(); 2].iter().cloned()); let a_start_loc = 0; let b_start_loc = len + 2; - let (mut new_memory, new_stack) = run_test("addmul_bignum", memory, vec![len.into(), a_start_loc.into(), b_start_loc.into(), c.into()])?; + let (mut new_memory, new_stack) = run_test( + "addmul_bignum", + memory, + vec![len.into(), a_start_loc.into(), b_start_loc.into(), c.into()], + )?; // Determine actual sum, appending the final carry if nonzero. let carry_limb = new_stack[0]; if carry_limb > 0.into() { new_memory[len] = carry_limb; } - let output = mem_vec_to_biguint(&new_memory[a_start_loc..a_start_loc+len]); + let output = mem_vec_to_biguint(&new_memory[a_start_loc..a_start_loc + len]); assert_eq!(output, expected_output); Ok(()) } -fn test_mul_bignum(a: BigUint, b: BigUint, expected_output: BigUint) -> Result<()> -{ +fn test_mul_bignum(a: BigUint, b: BigUint, expected_output: BigUint) -> Result<()> { let len = bignum_len(&a).max(bignum_len(&b)); let output_len = len * 2; let memory = pad_bignums(&[a.clone(), b.clone()], len); @@ -188,9 +208,18 @@ fn test_mul_bignum(a: BigUint, b: BigUint, expected_output: BigUint) -> Result<( let a_start_loc = 0; let b_start_loc = len; let output_start_loc = 2 * len; - let (new_memory, _new_stack) = run_test("mul_bignum", memory, vec![len.into(), a_start_loc.into(), b_start_loc.into(), output_start_loc.into()])?; + let (new_memory, _new_stack) = run_test( + "mul_bignum", + memory, + vec![ + len.into(), + a_start_loc.into(), + b_start_loc.into(), + output_start_loc.into(), + ], + )?; - let output = mem_vec_to_biguint(&new_memory[output_start_loc..output_start_loc+output_len]); + let output = mem_vec_to_biguint(&new_memory[output_start_loc..output_start_loc + output_len]); assert_eq!(output, expected_output); Ok(()) @@ -245,7 +274,13 @@ fn test_cmp_bignum_all() -> Result<()> { for bit_size in BIT_SIZES_TO_TEST { let a = gen_bignum(bit_size); let b = gen_bignum(bit_size); - let output = if a < b { MINUS_ONE } else if a == b { 0.into() } else { 1.into() }; + let output = if a < b { + MINUS_ONE + } else if a == b { + 0.into() + } else { + 1.into() + }; test_cmp_bignum(a, b, output)?; let a = max_bignum(bit_size); From e0a4bc31577f4004a75392940959072731b3954e Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 16 Mar 2023 11:21:30 -0700 Subject: [PATCH 47/62] cleanup --- evm/src/cpu/kernel/tests/bignum/mod.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum/mod.rs b/evm/src/cpu/kernel/tests/bignum/mod.rs index b504c9b0..b9f1d22e 100644 --- a/evm/src/cpu/kernel/tests/bignum/mod.rs +++ b/evm/src/cpu/kernel/tests/bignum/mod.rs @@ -39,7 +39,7 @@ fn test_data(filename: &str) -> Vec { let file = File::open(full_path(filename)).unwrap(); let lines = BufReader::new(file).lines(); lines - .map(|line| BigUint::parse_bytes(&line.unwrap().as_bytes(), 10).unwrap()) + .map(|line| BigUint::parse_bytes(line.unwrap().as_bytes(), 10).unwrap()) .collect() } @@ -103,7 +103,7 @@ fn run_test(fn_label: &str, memory: Vec, stack: Vec) -> Result<(Vec< fn test_shr_bignum(input: BigUint, expected_output: BigUint) -> Result<()> { let len = bignum_len(&input); - let memory = biguint_to_mem_vec(input.clone()); + let memory = biguint_to_mem_vec(input); let input_start_loc = 0; let (new_memory, _new_stack) = run_test( @@ -120,7 +120,7 @@ fn test_shr_bignum(input: BigUint, expected_output: BigUint) -> Result<()> { fn test_iszero_bignum(input: BigUint, expected_output: U256) -> Result<()> { let len = bignum_len(&input); - let memory = biguint_to_mem_vec(input.clone()); + let memory = biguint_to_mem_vec(input); let input_start_loc = 0; let (_new_memory, new_stack) = run_test( @@ -137,7 +137,7 @@ fn test_iszero_bignum(input: BigUint, expected_output: U256) -> Result<()> { fn test_cmp_bignum(a: BigUint, b: BigUint, expected_output: U256) -> Result<()> { let len = bignum_len(&a).max(bignum_len(&b)); - let memory = pad_bignums(&[a.clone(), b.clone()], len); + let memory = pad_bignums(&[a, b], len); let a_start_loc = 0; let b_start_loc = len; @@ -155,7 +155,7 @@ fn test_cmp_bignum(a: BigUint, b: BigUint, expected_output: U256) -> Result<()> fn test_add_bignum(a: BigUint, b: BigUint, expected_output: BigUint) -> Result<()> { let len = bignum_len(&a).max(bignum_len(&b)); - let memory = pad_bignums(&[a.clone(), b.clone()], len); + let memory = pad_bignums(&[a, b], len); let a_start_loc = 0; let b_start_loc = len; @@ -178,7 +178,7 @@ fn test_add_bignum(a: BigUint, b: BigUint, expected_output: BigUint) -> Result<( fn test_addmul_bignum(a: BigUint, b: BigUint, c: u128, expected_output: BigUint) -> Result<()> { let len = bignum_len(&a).max(bignum_len(&b)); - let mut memory = pad_bignums(&[a.clone(), b.clone()], len); + let mut memory = pad_bignums(&[a, b], len); memory.splice(len..len, vec![0.into(); 2].iter().cloned()); let a_start_loc = 0; @@ -203,7 +203,7 @@ fn test_addmul_bignum(a: BigUint, b: BigUint, c: u128, expected_output: BigUint) fn test_mul_bignum(a: BigUint, b: BigUint, expected_output: BigUint) -> Result<()> { let len = bignum_len(&a).max(bignum_len(&b)); let output_len = len * 2; - let memory = pad_bignums(&[a.clone(), b.clone()], len); + let memory = pad_bignums(&[a, b], len); let a_start_loc = 0; let b_start_loc = len; From 062eb82a8b185c4d4bd64bac536cf95d093ac243 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 16 Mar 2023 11:28:56 -0700 Subject: [PATCH 48/62] cleanup --- evm/src/cpu/kernel/tests/bignum/mod.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum/mod.rs b/evm/src/cpu/kernel/tests/bignum/mod.rs index b9f1d22e..26c6d8b1 100644 --- a/evm/src/cpu/kernel/tests/bignum/mod.rs +++ b/evm/src/cpu/kernel/tests/bignum/mod.rs @@ -274,12 +274,10 @@ fn test_cmp_bignum_all() -> Result<()> { for bit_size in BIT_SIZES_TO_TEST { let a = gen_bignum(bit_size); let b = gen_bignum(bit_size); - let output = if a < b { - MINUS_ONE - } else if a == b { - 0.into() - } else { - 1.into() + let output = match a.cmp(&b) { + Ordering::Less => U256::MINUS_ONE, + Ordering::Equal => 0.into(), + Ordering::Greater => 1.into(), }; test_cmp_bignum(a, b, output)?; From f1ad3da8ebf56cff9d62da24eb960f6083390864 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 16 Mar 2023 11:29:37 -0700 Subject: [PATCH 49/62] fix --- evm/src/cpu/kernel/tests/bignum/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/tests/bignum/mod.rs b/evm/src/cpu/kernel/tests/bignum/mod.rs index 26c6d8b1..67240d70 100644 --- a/evm/src/cpu/kernel/tests/bignum/mod.rs +++ b/evm/src/cpu/kernel/tests/bignum/mod.rs @@ -1,3 +1,4 @@ +use std::cmp::Ordering; use std::fs::File; use std::io::{BufRead, BufReader}; use std::path::PathBuf; @@ -275,7 +276,7 @@ fn test_cmp_bignum_all() -> Result<()> { let a = gen_bignum(bit_size); let b = gen_bignum(bit_size); let output = match a.cmp(&b) { - Ordering::Less => U256::MINUS_ONE, + Ordering::Less => MINUS_ONE, Ordering::Equal => 0.into(), Ordering::Greater => 1.into(), }; From b62bc35d646d0d64050e4cc66d4eeb1e2f8117c9 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 16 Mar 2023 11:39:19 -0700 Subject: [PATCH 50/62] fixes --- evm/src/cpu/kernel/asm/bignum/cmp.asm | 5 +++++ evm/src/cpu/kernel/tests/bignum/mod.rs | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/asm/bignum/cmp.asm b/evm/src/cpu/kernel/asm/bignum/cmp.asm index ff8fb3e6..840fceff 100644 --- a/evm/src/cpu/kernel/asm/bignum/cmp.asm +++ b/evm/src/cpu/kernel/asm/bignum/cmp.asm @@ -4,6 +4,11 @@ // Compares two bignums of the same given length. Assumes that len > 0. // 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 + ISZERO + %jumpi(equal) // stack: len, a_start_loc, b_start_loc, retdest SWAP1 // stack: a_start_loc, len, b_start_loc, retdest diff --git a/evm/src/cpu/kernel/tests/bignum/mod.rs b/evm/src/cpu/kernel/tests/bignum/mod.rs index 67240d70..12772db7 100644 --- a/evm/src/cpu/kernel/tests/bignum/mod.rs +++ b/evm/src/cpu/kernel/tests/bignum/mod.rs @@ -171,7 +171,9 @@ fn test_add_bignum(a: BigUint, b: BigUint, expected_output: BigUint) -> Result<( if carry_limb > 0.into() { new_memory[len] = carry_limb; } - let output = mem_vec_to_biguint(&new_memory[a_start_loc..a_start_loc + len]); + + let expected_output = biguint_to_mem_vec(expected_output); + let output = &new_memory[a_start_loc..a_start_loc + expected_output.len()]; assert_eq!(output, expected_output); Ok(()) From c59b979cdf8351a2ce01597a627bcb44a75f32b3 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 16 Mar 2023 11:42:39 -0700 Subject: [PATCH 51/62] addmul fix --- evm/src/cpu/kernel/tests/bignum/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/tests/bignum/mod.rs b/evm/src/cpu/kernel/tests/bignum/mod.rs index 12772db7..14de0945 100644 --- a/evm/src/cpu/kernel/tests/bignum/mod.rs +++ b/evm/src/cpu/kernel/tests/bignum/mod.rs @@ -197,7 +197,9 @@ fn test_addmul_bignum(a: BigUint, b: BigUint, c: u128, expected_output: BigUint) if carry_limb > 0.into() { new_memory[len] = carry_limb; } - let output = mem_vec_to_biguint(&new_memory[a_start_loc..a_start_loc + len]); + + let expected_output = biguint_to_mem_vec(expected_output); + let output = &new_memory[a_start_loc..a_start_loc + expected_output.len()]; assert_eq!(output, expected_output); Ok(()) From cecbfa9b591ef2a797a5df04f2ac5e2c145085ba Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 16 Mar 2023 11:46:01 -0700 Subject: [PATCH 52/62] fit --- evm/src/cpu/kernel/tests/bignum/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum/mod.rs b/evm/src/cpu/kernel/tests/bignum/mod.rs index 14de0945..a83a063c 100644 --- a/evm/src/cpu/kernel/tests/bignum/mod.rs +++ b/evm/src/cpu/kernel/tests/bignum/mod.rs @@ -171,7 +171,7 @@ fn test_add_bignum(a: BigUint, b: BigUint, expected_output: BigUint) -> Result<( if carry_limb > 0.into() { new_memory[len] = carry_limb; } - + let expected_output = biguint_to_mem_vec(expected_output); let output = &new_memory[a_start_loc..a_start_loc + expected_output.len()]; assert_eq!(output, expected_output); @@ -197,7 +197,7 @@ fn test_addmul_bignum(a: BigUint, b: BigUint, c: u128, expected_output: BigUint) if carry_limb > 0.into() { new_memory[len] = carry_limb; } - + let expected_output = biguint_to_mem_vec(expected_output); let output = &new_memory[a_start_loc..a_start_loc + expected_output.len()]; assert_eq!(output, expected_output); From 5720cf8a77003319b886d580f06c76a31e97422e Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 16 Mar 2023 15:40:40 -0700 Subject: [PATCH 53/62] updated function name --- evm/src/cpu/kernel/tests/bignum/mod.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum/mod.rs b/evm/src/cpu/kernel/tests/bignum/mod.rs index a83a063c..7fc676ef 100644 --- a/evm/src/cpu/kernel/tests/bignum/mod.rs +++ b/evm/src/cpu/kernel/tests/bignum/mod.rs @@ -36,7 +36,7 @@ fn full_path(filename: &str) -> PathBuf { path } -fn test_data(filename: &str) -> Vec { +fn test_data_biguint(filename: &str) -> Vec { let file = File::open(full_path(filename)).unwrap(); let lines = BufReader::new(file).lines(); lines @@ -242,8 +242,8 @@ fn test_shr_bignum_all() -> Result<()> { test_shr_bignum(input, output)?; } - let inputs = test_data(TEST_DATA_BIGNUM_INPUTS); - let shr_outputs = test_data(TEST_DATA_SHR_OUTPUTS); + let inputs = test_data_biguint(TEST_DATA_BIGNUM_INPUTS); + let shr_outputs = test_data_biguint(TEST_DATA_SHR_OUTPUTS); for (input, output) in inputs.iter().zip(shr_outputs.iter()) { test_shr_bignum(input.clone(), output.clone())?; } @@ -263,7 +263,7 @@ fn test_iszero_bignum_all() -> Result<()> { test_iszero_bignum(input, output.into())?; } - let inputs = test_data(TEST_DATA_BIGNUM_INPUTS); + let inputs = test_data_biguint(TEST_DATA_BIGNUM_INPUTS); let iszero_outputs = test_data_u256(TEST_DATA_ISZERO_OUTPUTS); let mut iszero_outputs_iter = iszero_outputs.iter(); for input in inputs { @@ -292,7 +292,7 @@ fn test_cmp_bignum_all() -> Result<()> { test_cmp_bignum(a, b, output)?; } - let inputs = test_data(TEST_DATA_BIGNUM_INPUTS); + let inputs = test_data_biguint(TEST_DATA_BIGNUM_INPUTS); let cmp_outputs = test_data_u256(TEST_DATA_CMP_OUTPUTS); let mut cmp_outputs_iter = cmp_outputs.iter(); for a in inputs.clone() { @@ -319,8 +319,8 @@ fn test_add_bignum_all() -> Result<()> { test_add_bignum(a, b, output)?; } - let inputs = test_data(TEST_DATA_BIGNUM_INPUTS); - let add_outputs = test_data(TEST_DATA_ADD_OUTPUTS); + let inputs = test_data_biguint(TEST_DATA_BIGNUM_INPUTS); + let add_outputs = test_data_biguint(TEST_DATA_ADD_OUTPUTS); let mut add_outputs_iter = add_outputs.iter(); for a in inputs.clone() { for b in inputs.clone() { @@ -350,9 +350,9 @@ fn test_addmul_bignum_all() -> Result<()> { test_addmul_bignum(a, b, c, output)?; } - let inputs = test_data(TEST_DATA_BIGNUM_INPUTS); + let inputs = test_data_biguint(TEST_DATA_BIGNUM_INPUTS); let u128_inputs = test_data_u128(TEST_DATA_U128_INPUTS); - let addmul_outputs = test_data(TEST_DATA_ADDMUL_OUTPUTS); + let addmul_outputs = test_data_biguint(TEST_DATA_ADDMUL_OUTPUTS); let mut addmul_outputs_iter = addmul_outputs.iter(); for a in inputs.clone() { for b in inputs.clone() { @@ -380,8 +380,8 @@ fn test_mul_bignum_all() -> Result<()> { test_mul_bignum(a, b, output)?; } - let inputs = test_data(TEST_DATA_BIGNUM_INPUTS); - let mul_outputs = test_data(TEST_DATA_MUL_OUTPUTS); + let inputs = test_data_biguint(TEST_DATA_BIGNUM_INPUTS); + let mul_outputs = test_data_biguint(TEST_DATA_MUL_OUTPUTS); let mut mul_outputs_iter = mul_outputs.iter(); for a in inputs.clone() { for b in inputs.clone() { From 2752456e5d803bb8972807d41e3b4306eaef2070 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Mon, 20 Mar 2023 12:31:36 -0700 Subject: [PATCH 54/62] addressed comments --- evm/src/cpu/kernel/tests/bignum/mod.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bignum/mod.rs b/evm/src/cpu/kernel/tests/bignum/mod.rs index 7fc676ef..57038e69 100644 --- a/evm/src/cpu/kernel/tests/bignum/mod.rs +++ b/evm/src/cpu/kernel/tests/bignum/mod.rs @@ -27,7 +27,7 @@ const TEST_DATA_ADD_OUTPUTS: &str = "add_outputs"; const TEST_DATA_ADDMUL_OUTPUTS: &str = "addmul_outputs"; const TEST_DATA_MUL_OUTPUTS: &str = "mul_outputs"; -const BIT_SIZES_TO_TEST: [usize; 4] = [128, 256, 512, 1000]; +const BIT_SIZES_TO_TEST: [usize; 15] = [0, 1, 2, 127, 128, 129, 255, 256, 257, 512, 1000, 1023, 1024, 1025, 31415]; fn full_path(filename: &str) -> PathBuf { let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); @@ -259,7 +259,7 @@ fn test_iszero_bignum_all() -> Result<()> { test_iszero_bignum(input, output.into())?; let input = max_bignum(bit_size); - let output = 0; + let output = bit_size.is_zero() as u8; test_iszero_bignum(input, output.into())?; } @@ -295,8 +295,8 @@ fn test_cmp_bignum_all() -> Result<()> { let inputs = test_data_biguint(TEST_DATA_BIGNUM_INPUTS); let cmp_outputs = test_data_u256(TEST_DATA_CMP_OUTPUTS); let mut cmp_outputs_iter = cmp_outputs.iter(); - for a in inputs.clone() { - for b in inputs.clone() { + for a in &inputs { + for b in &inputs { let output = cmp_outputs_iter.next().unwrap(); test_cmp_bignum(a.clone(), b.clone(), *output)?; } @@ -322,8 +322,8 @@ fn test_add_bignum_all() -> Result<()> { let inputs = test_data_biguint(TEST_DATA_BIGNUM_INPUTS); let add_outputs = test_data_biguint(TEST_DATA_ADD_OUTPUTS); let mut add_outputs_iter = add_outputs.iter(); - for a in inputs.clone() { - for b in inputs.clone() { + for a in &inputs { + for b in &inputs { let output = add_outputs_iter.next().unwrap(); test_add_bignum(a.clone(), b.clone(), output.clone())?; } @@ -354,11 +354,11 @@ fn test_addmul_bignum_all() -> Result<()> { let u128_inputs = test_data_u128(TEST_DATA_U128_INPUTS); let addmul_outputs = test_data_biguint(TEST_DATA_ADDMUL_OUTPUTS); let mut addmul_outputs_iter = addmul_outputs.iter(); - for a in inputs.clone() { - for b in inputs.clone() { - for c in u128_inputs.clone() { + for a in &inputs { + for b in &inputs { + for c in &u128_inputs { let output = addmul_outputs_iter.next().unwrap(); - test_addmul_bignum(a.clone(), b.clone(), c, output.clone())?; + test_addmul_bignum(a.clone(), b.clone(), c.clone(), output.clone())?; } } } @@ -383,8 +383,8 @@ fn test_mul_bignum_all() -> Result<()> { let inputs = test_data_biguint(TEST_DATA_BIGNUM_INPUTS); let mul_outputs = test_data_biguint(TEST_DATA_MUL_OUTPUTS); let mut mul_outputs_iter = mul_outputs.iter(); - for a in inputs.clone() { - for b in inputs.clone() { + for a in &inputs { + for b in &inputs { let output = mul_outputs_iter.next().unwrap(); test_mul_bignum(a.clone(), b.clone(), output.clone())?; } From 72b5bb0eac6c1559efa5124ad0c8bb8abbdb0dad Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Mon, 20 Mar 2023 12:31:41 -0700 Subject: [PATCH 55/62] fmt --- evm/src/cpu/kernel/tests/bignum/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/tests/bignum/mod.rs b/evm/src/cpu/kernel/tests/bignum/mod.rs index 57038e69..a689b352 100644 --- a/evm/src/cpu/kernel/tests/bignum/mod.rs +++ b/evm/src/cpu/kernel/tests/bignum/mod.rs @@ -27,7 +27,9 @@ const TEST_DATA_ADD_OUTPUTS: &str = "add_outputs"; const TEST_DATA_ADDMUL_OUTPUTS: &str = "addmul_outputs"; const TEST_DATA_MUL_OUTPUTS: &str = "mul_outputs"; -const BIT_SIZES_TO_TEST: [usize; 15] = [0, 1, 2, 127, 128, 129, 255, 256, 257, 512, 1000, 1023, 1024, 1025, 31415]; +const BIT_SIZES_TO_TEST: [usize; 15] = [ + 0, 1, 2, 127, 128, 129, 255, 256, 257, 512, 1000, 1023, 1024, 1025, 31415, +]; fn full_path(filename: &str) -> PathBuf { let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); From f6b9d6ee2e57b1622010dd3bafbd2e43451947d1 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Mon, 20 Mar 2023 12:36:07 -0700 Subject: [PATCH 56/62] addressed comments --- evm/src/cpu/kernel/asm/util/basic_macros.asm | 8 -------- evm/src/cpu/kernel/tests/bignum/mod.rs | 2 +- plonky2/src/fri/recursive_verifier.rs | 8 ++++++-- plonky2/src/gadgets/split_base.rs | 3 ++- plonky2/src/gates/random_access.rs | 4 +++- plonky2/src/hash/merkle_tree.rs | 4 +++- plonky2/src/iop/generator.rs | 3 ++- plonky2/src/iop/witness.rs | 6 ++++-- 8 files changed, 21 insertions(+), 17 deletions(-) diff --git a/evm/src/cpu/kernel/asm/util/basic_macros.asm b/evm/src/cpu/kernel/asm/util/basic_macros.asm index 3f4c4c69..50857eaa 100644 --- a/evm/src/cpu/kernel/asm/util/basic_macros.asm +++ b/evm/src/cpu/kernel/asm/util/basic_macros.asm @@ -50,14 +50,6 @@ %endrep %endmacro -%macro neq - // stack: x, y - EQ - // stack: x == y - ISZERO - // stack: x != y -%endmacro - %macro and_const(c) // stack: input, ... PUSH $c diff --git a/evm/src/cpu/kernel/tests/bignum/mod.rs b/evm/src/cpu/kernel/tests/bignum/mod.rs index a689b352..4b1a7460 100644 --- a/evm/src/cpu/kernel/tests/bignum/mod.rs +++ b/evm/src/cpu/kernel/tests/bignum/mod.rs @@ -360,7 +360,7 @@ fn test_addmul_bignum_all() -> Result<()> { for b in &inputs { for c in &u128_inputs { let output = addmul_outputs_iter.next().unwrap(); - test_addmul_bignum(a.clone(), b.clone(), c.clone(), output.clone())?; + test_addmul_bignum(a.clone(), b.clone(), *c, output.clone())?; } } } diff --git a/plonky2/src/fri/recursive_verifier.rs b/plonky2/src/fri/recursive_verifier.rs index 307c4785..8e9329d5 100644 --- a/plonky2/src/fri/recursive_verifier.rs +++ b/plonky2/src/fri/recursive_verifier.rs @@ -78,12 +78,16 @@ impl, const D: usize> CircuitBuilder { assert!( self.config.num_wires >= min_wires, - "To efficiently perform FRI checks with an arity of 2^{max_fri_arity_bits}, at least {min_wires} wires are needed. Consider reducing arity." + "To efficiently perform FRI checks with an arity of 2^{}, at least {} wires are needed. Consider reducing arity.", + max_fri_arity_bits, + min_wires ); assert!( self.config.num_routed_wires >= min_routed_wires, - "To efficiently perform FRI checks with an arity of 2^{max_fri_arity_bits}, at least {min_routed_wires} routed wires are needed. Consider reducing arity." + "To efficiently perform FRI checks with an arity of 2^{}, at least {} routed wires are needed. Consider reducing arity.", + max_fri_arity_bits, + min_routed_wires ); } diff --git a/plonky2/src/gadgets/split_base.rs b/plonky2/src/gadgets/split_base.rs index 7558be3d..dd0edf5d 100644 --- a/plonky2/src/gadgets/split_base.rs +++ b/plonky2/src/gadgets/split_base.rs @@ -38,7 +38,8 @@ impl, const D: usize> CircuitBuilder { let num_bits = bits.len(); assert!( num_bits <= log_floor(F::ORDER, 2), - "{num_bits} bits may overflow the field" + "{} bits may overflow the field", + num_bits ); if num_bits == 0 { return self.zero(); diff --git a/plonky2/src/gates/random_access.rs b/plonky2/src/gates/random_access.rs index b74b1169..80874505 100644 --- a/plonky2/src/gates/random_access.rs +++ b/plonky2/src/gates/random_access.rs @@ -361,7 +361,9 @@ impl, const D: usize> SimpleGenerator let access_index = access_index_f.to_canonical_u64() as usize; debug_assert!( access_index < vec_size, - "Access index {access_index} is larger than the vector size {vec_size}" + "Access index {} is larger than the vector size {}", + access_index, + vec_size ); set_local_wire( diff --git a/plonky2/src/hash/merkle_tree.rs b/plonky2/src/hash/merkle_tree.rs index beb22b07..e884554f 100644 --- a/plonky2/src/hash/merkle_tree.rs +++ b/plonky2/src/hash/merkle_tree.rs @@ -136,7 +136,9 @@ impl> MerkleTree { let log2_leaves_len = log2_strict(leaves.len()); assert!( cap_height <= log2_leaves_len, - "cap_height={cap_height} should be at most log2(leaves.len())={log2_leaves_len}" + "cap_height={} should be at most log2(leaves.len())={}", + cap_height, + log2_leaves_len ); let num_digests = 2 * (leaves.len() - (1 << cap_height)); diff --git a/plonky2/src/iop/generator.rs b/plonky2/src/iop/generator.rs index 80eb0094..a65d1748 100644 --- a/plonky2/src/iop/generator.rs +++ b/plonky2/src/iop/generator.rs @@ -89,7 +89,8 @@ pub(crate) fn generate_partial_witness< assert_eq!( remaining_generators, 0, - "{remaining_generators} generators weren't run", + "{} generators weren't run", + remaining_generators, ); witness diff --git a/plonky2/src/iop/witness.rs b/plonky2/src/iop/witness.rs index d0e3e7e4..14213d0d 100644 --- a/plonky2/src/iop/witness.rs +++ b/plonky2/src/iop/witness.rs @@ -284,7 +284,8 @@ impl WitnessWrite for PartialWitness { if let Some(old_value) = opt_old_value { assert_eq!( value, old_value, - "Target {target:?} was set twice with different values: {old_value} != {value}" + "Target {:?} was set twice with different values: {} != {}", + target, old_value, value ); } } @@ -324,7 +325,8 @@ impl<'a, F: Field> PartitionWitness<'a, F> { if let Some(old_value) = *rep_value { assert_eq!( value, old_value, - "Partition containing {target:?} was set twice with different values: {old_value} != {value}" + "Partition containing {:?} was set twice with different values: {} != {}", + target, old_value, value ); None } else { From a5fad9ebc078f15b279c7bc0af789dd2934275b2 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Mon, 20 Mar 2023 12:36:48 -0700 Subject: [PATCH 57/62] addressed comments --- evm/src/keccak/keccak_stark.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/src/keccak/keccak_stark.rs b/evm/src/keccak/keccak_stark.rs index 61651dd5..c8fe8086 100644 --- a/evm/src/keccak/keccak_stark.rs +++ b/evm/src/keccak/keccak_stark.rs @@ -68,7 +68,7 @@ impl, const D: usize> KeccakStark { let pad_rows = self.generate_trace_rows_for_perm([0; NUM_INPUTS]); while rows.len() < num_rows { - rows.extend(pad_rows.clone()); + rows.extend(&pad_rows); } rows.drain(num_rows..); rows From 652b2bedad1eccc64853dae17acab6bdb9230b59 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Mon, 20 Mar 2023 12:37:37 -0700 Subject: [PATCH 58/62] allow empty stack replacement --- evm/src/cpu/kernel/evm_asm.pest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/evm_asm.pest b/evm/src/cpu/kernel/evm_asm.pest index e7337430..3243aecc 100644 --- a/evm/src/cpu/kernel/evm_asm.pest +++ b/evm/src/cpu/kernel/evm_asm.pest @@ -26,7 +26,7 @@ stack = { ^"%stack" ~ stack_placeholders ~ "->" ~ stack_replacements } stack_placeholders = { "(" ~ (stack_placeholder ~ ("," ~ stack_placeholder)*)? ~ ")" } stack_placeholder = { stack_block | identifier } stack_block = { identifier ~ ":" ~ literal_decimal } -stack_replacements = { "(" ~ stack_replacement ~ ("," ~ stack_replacement)* ~ ")" } +stack_replacements = { "(" ~ (stack_replacement ~ ("," ~ stack_replacement)*)? ~ ")" } stack_replacement = { literal | identifier | constant | macro_label | variable } global_label_decl = ${ ^"GLOBAL " ~ identifier ~ ":" } From 3c4bc1d8246107060b0008255f31a4aa2ff286b1 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Mon, 20 Mar 2023 18:02:20 -0700 Subject: [PATCH 59/62] Fix GAS and implement storage value parsing --- evm/src/cpu/kernel/asm/mpt/load/load_trie_specific.asm | 5 ++++- evm/src/witness/transition.rs | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/asm/mpt/load/load_trie_specific.asm b/evm/src/cpu/kernel/asm/mpt/load/load_trie_specific.asm index b93b36e4..80c6dbbe 100644 --- a/evm/src/cpu/kernel/asm/mpt/load/load_trie_specific.asm +++ b/evm/src/cpu/kernel/asm/mpt/load/load_trie_specific.asm @@ -37,4 +37,7 @@ global mpt_load_receipt_trie_value: global mpt_load_storage_trie_value: // stack: retdest - PANIC // TODO + PROVER_INPUT(mpt) + %append_to_trie_data + // stack: retdest + JUMP diff --git a/evm/src/witness/transition.rs b/evm/src/witness/transition.rs index d48561db..be6aba94 100644 --- a/evm/src/witness/transition.rs +++ b/evm/src/witness/transition.rs @@ -108,6 +108,7 @@ fn decode(registers: RegistersState, opcode: u8) -> Result Ok(Operation::Jumpi), (0x58, _) => Ok(Operation::Pc), (0x59, _) => Ok(Operation::Syscall(opcode)), + (0x5a, _) => Ok(Operation::Syscall(opcode)), (0x5b, _) => Ok(Operation::Jumpdest), (0x60..=0x7f, _) => Ok(Operation::Push(opcode & 0x1f)), (0x80..=0x8f, _) => Ok(Operation::Dup(opcode & 0xf)), From 893b88c309e073bc370b439c26da8f0f9d01f6c1 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 21 Mar 2023 05:54:29 +0100 Subject: [PATCH 60/62] Implement syscalls for BALANCE and SELFBALANCE (#922) * Implement syscalls for BALANCE and SELFBALANCE * Remove stubs --- evm/src/cpu/kernel/asm/balance.asm | 35 +++++++++++++++---- evm/src/cpu/kernel/asm/core/syscall_stubs.asm | 4 --- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/evm/src/cpu/kernel/asm/balance.asm b/evm/src/cpu/kernel/asm/balance.asm index 6ce88cc4..1c7fb400 100644 --- a/evm/src/cpu/kernel/asm/balance.asm +++ b/evm/src/cpu/kernel/asm/balance.asm @@ -1,3 +1,20 @@ +global sys_balance: + // stack: kexit_info, address + // TODO: assuming a cold account access for now. + %charge_gas_const(@GAS_COLDACCOUNTACCESS) + SWAP1 + // stack: address, kexit_info + %balance + // stack: balance, kexit_info + SWAP1 + EXIT_KERNEL + +%macro balance + %stack (address) -> (address, %%after) + %jump(balance) +%%after: +%endmacro + global balance: // stack: address, retdest %mpt_read_state_trie @@ -13,11 +30,17 @@ retzero: %stack (account_ptr, retdest) -> (retdest, 0) JUMP +global sys_selfbalance: + // stack: kexit_info + %charge_gas_const(@GAS_LOW) + %selfbalance + // stack: balance, kexit_info + SWAP1 + EXIT_KERNEL -global selfbalance: - // stack: retdest +%macro selfbalance + PUSH %%after %address - PUSH balance - // stack: balance, address, retdest - JUMP - + %jump(balance) +%%after: +%endmacro \ No newline at end of file diff --git a/evm/src/cpu/kernel/asm/core/syscall_stubs.asm b/evm/src/cpu/kernel/asm/core/syscall_stubs.asm index 26281eea..610c7502 100644 --- a/evm/src/cpu/kernel/asm/core/syscall_stubs.asm +++ b/evm/src/cpu/kernel/asm/core/syscall_stubs.asm @@ -13,8 +13,6 @@ global sys_sgt: PANIC global sys_sar: PANIC -global sys_balance: - PANIC global sys_origin: PANIC global sys_calldatasize: @@ -50,8 +48,6 @@ global sys_chainid: // stack: chain_id, kexit_info SWAP1 EXIT_KERNEL -global sys_selfbalance: - PANIC global sys_basefee: PANIC global sys_log0: From afded1682b13c1d8adf45d7c4ebb2cc94b4ac4e3 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Mon, 20 Mar 2023 21:40:58 -0700 Subject: [PATCH 61/62] Contract creation fixes --- evm/src/cpu/kernel/asm/balance.asm | 2 +- evm/src/cpu/kernel/asm/core/create.asm | 14 ++- .../cpu/kernel/asm/core/create_addresses.asm | 24 +++- evm/src/cpu/kernel/asm/core/nonce.asm | 26 +++-- evm/src/cpu/kernel/asm/core/process_txn.asm | 103 ++++++++++++++---- evm/src/cpu/kernel/asm/core/terminate.asm | 11 +- .../asm/mpt/insert/insert_trie_specific.asm | 6 + .../cpu/kernel/asm/transactions/type_0.asm | 2 +- evm/src/generation/state.rs | 10 +- 9 files changed, 149 insertions(+), 49 deletions(-) diff --git a/evm/src/cpu/kernel/asm/balance.asm b/evm/src/cpu/kernel/asm/balance.asm index 1c7fb400..1c6429d2 100644 --- a/evm/src/cpu/kernel/asm/balance.asm +++ b/evm/src/cpu/kernel/asm/balance.asm @@ -43,4 +43,4 @@ global sys_selfbalance: %address %jump(balance) %%after: -%endmacro \ No newline at end of file +%endmacro diff --git a/evm/src/cpu/kernel/asm/core/create.asm b/evm/src/cpu/kernel/asm/core/create.asm index cc37f832..d7e6eed2 100644 --- a/evm/src/cpu/kernel/asm/core/create.asm +++ b/evm/src/cpu/kernel/asm/core/create.asm @@ -1,3 +1,7 @@ +// TODO: This file needs to be cleaned up. +// `create` is no longer being used for contract-creation txns, +// so it can be inlined. Also need to set metadata on new ctx. + // The CREATE syscall. // // Pre stack: kexit_info, value, code_offset, code_len @@ -24,8 +28,8 @@ sys_create_finish: // Note: CODE_ADDR refers to a (context, segment, offset) tuple. global create: // stack: sender, endowment, CODE_ADDR, code_len, retdest - // TODO: Charge gas. - DUP1 %get_nonce + DUP1 %nonce + // stack: nonce, sender, endowment, CODE_ADDR, code_len, retdest // Call get_create_address and have it return to create_inner. %stack (nonce, sender) @@ -67,12 +71,14 @@ sys_create2_finish: // Pre stack: address, sender, endowment, CODE_ADDR, code_len, retdest // Post stack: address // Note: CODE_ADDR refers to a (context, segment, offset) tuple. -create_inner: +global create_inner: // stack: address, sender, endowment, CODE_ADDR, code_len, retdest %stack (address, sender, endowment) -> (sender, address, endowment, sender, address) - // TODO: Need to handle insufficient balance failure. + %transfer_eth + // stack: transfer_eth_status, sender, address, CODE_ADDR, code_len, retdest + %jumpi(fault_exception) // stack: sender, address, CODE_ADDR, code_len, retdest %increment_nonce diff --git a/evm/src/cpu/kernel/asm/core/create_addresses.asm b/evm/src/cpu/kernel/asm/core/create_addresses.asm index 67fd65a6..8aad8e28 100644 --- a/evm/src/cpu/kernel/asm/core/create_addresses.asm +++ b/evm/src/cpu/kernel/asm/core/create_addresses.asm @@ -5,14 +5,32 @@ // Post stack: address global get_create_address: // stack: sender, nonce, retdest - // TODO: Replace with actual implementation. - %pop2 - PUSH 123 + %alloc_rlp_block + // stack: rlp_start, sender, nonce, retdest + %stack (rlp_start, sender, nonce) -> (rlp_start, sender, nonce, rlp_start) + // stack: rlp_start, sender, nonce, rlp_start, retdest + %encode_rlp_160 // TODO: or encode_rlp_scalar? + // stack: rlp_pos, nonce, rlp_start, retdest + %encode_rlp_scalar + // stack: rlp_pos, rlp_start, retdest + %prepend_rlp_list_prefix + // stack: rlp_prefix_start, rlp_len, retdest + PUSH @SEGMENT_RLP_RAW + PUSH 0 // context + // stack: RLP_ADDR: 3, rlp_len, retdest + KECCAK_GENERAL // stack: address, retdest %observe_new_address SWAP1 JUMP +// Convenience macro to call get_create_address and return where we left off. +%macro get_create_address + %stack (sender, nonce) -> (sender, nonce, %%after) + %jump(get_create_address) +%%after: +%endmacro + // Computes the address for a contract based on the CREATE2 rule, i.e. // address = KEC(0xff || sender || salt || code_hash)[12:] // diff --git a/evm/src/cpu/kernel/asm/core/nonce.asm b/evm/src/cpu/kernel/asm/core/nonce.asm index 042d81f3..973a032d 100644 --- a/evm/src/cpu/kernel/asm/core/nonce.asm +++ b/evm/src/cpu/kernel/asm/core/nonce.asm @@ -1,17 +1,21 @@ -// Increment the nonce of the given account. +// Get the nonce of the given account. // Pre stack: address, retdest // Post stack: (empty) - -global get_nonce: +global nonce: // stack: address, retdest - // TODO: Replace with actual implementation. - POP - JUMP + %mpt_read_state_trie + // stack: account_ptr, retdest + // The nonce is the first account field, so we deref the account pointer itself. + // Note: We don't need to handle account_ptr=0, as trie_data[0] = 0, + // so the deref will give 0 (the default nonce) as desired. + %mload_trie_data + // stack: nonce, retdest + SWAP1 JUMP -// Convenience macro to call get_nonce and return where we left off. -%macro get_nonce +// Convenience macro to call nonce and return where we left off. +%macro nonce %stack (address) -> (address, %%after) - %jump(get_nonce) + %jump(nonce) %%after: %endmacro @@ -20,7 +24,7 @@ global increment_nonce: // stack: address, retdest %mpt_read_state_trie // stack: account_ptr, retdest - DUP1 ISZERO %jumpi(panic) + DUP1 ISZERO %jumpi(increment_nonce_no_such_account) // stack: nonce_ptr, retdest DUP1 %mload_trie_data // stack: nonce, nonce_ptr, retdest @@ -30,6 +34,8 @@ global increment_nonce: %mstore_trie_data // stack: retdest JUMP +global increment_nonce_no_such_account: + PANIC // Convenience macro to call increment_nonce and return where we left off. %macro increment_nonce diff --git a/evm/src/cpu/kernel/asm/core/process_txn.asm b/evm/src/cpu/kernel/asm/core/process_txn.asm index 9629d647..acce98f9 100644 --- a/evm/src/cpu/kernel/asm/core/process_txn.asm +++ b/evm/src/cpu/kernel/asm/core/process_txn.asm @@ -50,23 +50,76 @@ global process_based_on_type: global process_contract_creation_txn: // stack: retdest - PUSH process_contract_creation_txn_after_create - // stack: process_contract_creation_txn_after_create, retdest - %mload_txn_field(@TXN_FIELD_DATA_LEN) - // stack: code_len, process_contract_creation_txn_after_create, retdest - PUSH 0 - // stack: code_offset, code_len, process_contract_creation_txn_after_create, retdest - PUSH @SEGMENT_TXN_DATA - // stack: code_segment, code_offset, code_len, process_contract_creation_txn_after_create, retdest - PUSH 0 // context - // stack: CODE_ADDR, code_len, process_contract_creation_txn_after_create, retdest + + %mload_txn_field(@TXN_FIELD_ORIGIN) + // stack: origin, retdest + DUP1 %nonce + // stack: origin_nonce, origin, retdest + SWAP1 + // stack: origin, origin_nonce, retdest + %get_create_address + // stack: address, retdest + + // Deduct value from caller. %mload_txn_field(@TXN_FIELD_VALUE) %mload_txn_field(@TXN_FIELD_ORIGIN) - // stack: sender, endowment, CODE_ADDR, code_len, process_contract_creation_txn_after_create, retdest - %jump(create) + %deduct_eth + // stack: deduct_eth_status, address, retdest + %jumpi(panic) + // stack: address, retdest -global process_contract_creation_txn_after_create: - // stack: new_address, retdest + // Write the new account's data to MPT data, and get a pointer to it. + %get_trie_data_size + // stack: account_ptr, address, retdest + PUSH 1 %append_to_trie_data // nonce = 1 + // stack: account_ptr, address, retdest + DUP2 %balance %mload_txn_field(@TXN_FIELD_VALUE) ADD %append_to_trie_data // balance = old_balance + txn_value + // stack: account_ptr, address, retdest + PUSH 0 %append_to_trie_data // storage_root = nil + // stack: account_ptr, address, retdest + PUSH @EMPTY_STRING_HASH %append_to_trie_data // code_hash = keccak('') + // stack: account_ptr, address, retdest + DUP2 + // stack: address, account_ptr, address, retdest + %mpt_insert_state_trie + // stack: address, retdest + + %create_context + // stack: new_ctx, address, retdest + + // Copy the code from txdata to the new context's code segment. + PUSH process_contract_creation_txn_after_code_loaded + %mload_txn_field(@TXN_FIELD_DATA_LEN) + PUSH 0 // SRC.offset + PUSH @SEGMENT_TXN_DATA // SRC.segment + PUSH 0 // SRC.context + PUSH 0 // DST.offset + PUSH @SEGMENT_CODE // DST.segment + DUP7 // DST.context = new_ctx + %jump(memcpy) + +process_contract_creation_txn_after_code_loaded: + // stack: new_ctx, address, retdest + + // Each line in the block below does not change the stack. + DUP2 %set_new_ctx_addr + %mload_txn_field(@TXN_FIELD_ORIGIN) %set_new_ctx_caller + %mload_txn_field(@TXN_FIELD_VALUE) %set_new_ctx_value + %set_new_ctx_parent_ctx + %set_new_ctx_parent_pc(process_contract_creation_txn_after_constructor) + %non_intrinisic_gas %set_new_ctx_gas_limit + // stack: new_ctx, address, retdest + + %enter_new_ctx + // (Old context) stack: new_ctx, address, retdest + +global process_contract_creation_txn_after_constructor: + // stack: success, leftover_gas, new_ctx, address, retdest + POP // TODO: Success will go into the receipt when we support that. + // stack: leftover_gas, new_ctx, address, retdest + %pay_coinbase_and_refund_sender + // stack: new_ctx, address, retdest + POP POP JUMP @@ -105,9 +158,8 @@ global process_message_txn_insufficient_balance: global process_message_txn_return: // stack: retdest - %mload_txn_field(@TXN_FIELD_INTRINSIC_GAS) - %mload_txn_field(@TXN_FIELD_GAS_LIMIT) - SUB + // Since no code was executed, the leftover gas is the non-intrinsic gas. + %non_intrinisic_gas // stack: leftover_gas, retdest %pay_coinbase_and_refund_sender // stack: retdest @@ -124,18 +176,13 @@ global process_message_txn_code_loaded: %mload_txn_field(@TXN_FIELD_VALUE) %set_new_ctx_value %set_new_ctx_parent_ctx %set_new_ctx_parent_pc(process_message_txn_after_call) - // stack: new_ctx, retdest - - // The gas provided to the callee is gas_limit - intrinsic_gas. - %mload_txn_field(@TXN_FIELD_INTRINSIC_GAS) - %mload_txn_field(@TXN_FIELD_GAS_LIMIT) - SUB - %set_new_ctx_gas_limit + %non_intrinisic_gas %set_new_ctx_gas_limit // stack: new_ctx, retdest // TODO: Copy TXN_DATA to CALLDATA %enter_new_ctx + // (Old context) stack: new_ctx, retdest global process_message_txn_after_call: // stack: success, leftover_gas, new_ctx, retdest @@ -206,3 +253,11 @@ global process_message_txn_after_call: %mstore_txn_field(@TXN_FIELD_COMPUTED_PRIORITY_FEE_PER_GAS) // stack: (empty) %endmacro + +%macro non_intrinisic_gas + // stack: (empty) + %mload_txn_field(@TXN_FIELD_INTRINSIC_GAS) + %mload_txn_field(@TXN_FIELD_GAS_LIMIT) + SUB + // stack: gas_limit - intrinsic_gas +%endmacro diff --git a/evm/src/cpu/kernel/asm/core/terminate.asm b/evm/src/cpu/kernel/asm/core/terminate.asm index 4a3fbf02..26fb113c 100644 --- a/evm/src/cpu/kernel/asm/core/terminate.asm +++ b/evm/src/cpu/kernel/asm/core/terminate.asm @@ -97,6 +97,15 @@ global terminate_common: %shr_const(192) // stack: gas_used %mload_context_metadata(@CTX_METADATA_GAS_LIMIT) + // stack: gas_limit, gas_used + SWAP1 + // stack: gas_used, gas_limit + DUP2 DUP2 LT + // stack: gas_used < gas_limit, gas_used, gas_limit + SWAP2 + // stack: gas_limit, gas_used, gas_used < gas_limit SUB - // stack: leftover_gas + // stack: gas_limit - gas_used, gas_used < gas_limit + MUL + // stack: leftover_gas = (gas_limit - gas_used) * (gas_used < gas_limit) %endmacro diff --git a/evm/src/cpu/kernel/asm/mpt/insert/insert_trie_specific.asm b/evm/src/cpu/kernel/asm/mpt/insert/insert_trie_specific.asm index 225f3cc0..60df845e 100644 --- a/evm/src/cpu/kernel/asm/mpt/insert/insert_trie_specific.asm +++ b/evm/src/cpu/kernel/asm/mpt/insert/insert_trie_specific.asm @@ -15,3 +15,9 @@ mpt_insert_state_trie_save: // stack: updated_node_ptr, retdest %mstore_global_metadata(@GLOBAL_METADATA_STATE_TRIE_ROOT) JUMP + +%macro mpt_insert_state_trie + %stack (key, value_ptr) -> (key, value_ptr, %%after) + %jump(mpt_insert_state_trie) +%%after: +%endmacro diff --git a/evm/src/cpu/kernel/asm/transactions/type_0.asm b/evm/src/cpu/kernel/asm/transactions/type_0.asm index d00b10d4..45c57361 100644 --- a/evm/src/cpu/kernel/asm/transactions/type_0.asm +++ b/evm/src/cpu/kernel/asm/transactions/type_0.asm @@ -102,7 +102,7 @@ type_0_compute_signed_data: // stack: rlp_pos, rlp_start, retdest %mload_txn_field(@TXN_FIELD_TO) - SWAP1 %encode_rlp_160 + SWAP1 %encode_rlp_scalar // stack: rlp_pos, rlp_start, retdest %mload_txn_field(@TXN_FIELD_VALUE) diff --git a/evm/src/generation/state.rs b/evm/src/generation/state.rs index 9399e4b6..26a0ac81 100644 --- a/evm/src/generation/state.rs +++ b/evm/src/generation/state.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use ethereum_types::{Address, H160, H256, U256}; +use ethereum_types::{Address, BigEndianHash, H160, H256, U256}; use keccak_hash::keccak; use plonky2::field::types::Field; @@ -72,10 +72,10 @@ impl GenerationState { pub fn jump_to(&mut self, dst: usize) { self.registers.program_counter = dst; if dst == KERNEL.global_labels["observe_new_address"] { - let address = stack_peek(self, 0).expect("Empty stack"); - let mut address_bytes = [0; 20]; - address.to_big_endian(&mut address_bytes); - self.observe_address(H160(address_bytes)); + let tip_u256 = stack_peek(self, 0).expect("Empty stack"); + let tip_h256 = H256::from_uint(&tip_u256); + let tip_h160 = H160::from(tip_h256); + self.observe_address(tip_h160); } } From e1ae539271827e091819f83abc4d7ff8fe1a7faf Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Mon, 20 Mar 2023 23:57:44 -0700 Subject: [PATCH 62/62] Fix test --- evm/src/cpu/kernel/asm/core/create_addresses.asm | 1 + evm/src/cpu/kernel/tests/core/create_addresses.rs | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/evm/src/cpu/kernel/asm/core/create_addresses.asm b/evm/src/cpu/kernel/asm/core/create_addresses.asm index 8aad8e28..7dd4e889 100644 --- a/evm/src/cpu/kernel/asm/core/create_addresses.asm +++ b/evm/src/cpu/kernel/asm/core/create_addresses.asm @@ -19,6 +19,7 @@ global get_create_address: PUSH 0 // context // stack: RLP_ADDR: 3, rlp_len, retdest KECCAK_GENERAL + %mod_const(0x10000000000000000000000000000000000000000) // 2^160 // stack: address, retdest %observe_new_address SWAP1 diff --git a/evm/src/cpu/kernel/tests/core/create_addresses.rs b/evm/src/cpu/kernel/tests/core/create_addresses.rs index 047ddc00..03d780d8 100644 --- a/evm/src/cpu/kernel/tests/core/create_addresses.rs +++ b/evm/src/cpu/kernel/tests/core/create_addresses.rs @@ -1,4 +1,6 @@ use anyhow::Result; +use ethereum_types::U256; +use hex_literal::hex; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; @@ -7,11 +9,11 @@ use crate::cpu::kernel::interpreter::Interpreter; fn test_get_create_address() -> Result<()> { let get_create_address = KERNEL.global_labels["get_create_address"]; - // TODO: Replace with real data once we have a real implementation. + // This is copied from OpenEthereum's `test_contract_address`. let retaddr = 0xdeadbeefu32.into(); - let nonce = 5.into(); - let sender = 0.into(); - let expected_addr = 123.into(); + let nonce = 88.into(); + let sender = U256::from_big_endian(&hex!("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6")); + let expected_addr = U256::from_big_endian(&hex!("3f09c73a5ed19289fb9bdc72f1742566df146f56")); let initial_stack = vec![retaddr, nonce, sender]; let mut interpreter = Interpreter::new_with_kernel(get_create_address, initial_stack);