From a86b4fd378c62f74b52a10654c3d95e05eb6cf36 Mon Sep 17 00:00:00 2001 From: Andrey Khmuro Date: Thu, 9 Nov 2023 13:40:09 +0100 Subject: [PATCH 1/2] refactor: remove checked instructions from math::u64 --- assembly/README.md | 2 +- assembly/src/ast/tests.rs | 8 +- .../user_docs/assembly/code_organization.md | 4 +- docs/src/user_docs/stdlib/math/u64.md | 69 ++- stdlib/asm/math/u64.masm | 325 ++------------ stdlib/docs/math/u64.md | 65 +-- stdlib/tests/math/u64_mod.rs | 421 ++---------------- 7 files changed, 136 insertions(+), 758 deletions(-) diff --git a/assembly/README.md b/assembly/README.md index c78f9c97a1..9d26fca606 100644 --- a/assembly/README.md +++ b/assembly/README.md @@ -43,7 +43,7 @@ use.std::math::u64 begin push.1.0 push.2.0 - exec.u64::checked_add + exec.u64::wrapping_add end ``` diff --git a/assembly/src/ast/tests.rs b/assembly/src/ast/tests.rs index 2b55f25bd0..4644d9aaa0 100644 --- a/assembly/src/ast/tests.rs +++ b/assembly/src/ast/tests.rs @@ -898,7 +898,7 @@ fn test_ast_program_serde_imports_serialized() { begin push.0 push.1 - exec.u64::checked_add + exec.u64::wrapping_add end"; assert_correct_program_serialization(source, true); } @@ -912,7 +912,7 @@ fn test_ast_program_serde_imports_not_serialized() { begin push.0 push.1 - exec.u64::checked_add + exec.u64::wrapping_add end"; assert_correct_program_serialization(source, false); } @@ -926,7 +926,7 @@ fn test_ast_module_serde_imports_serialized() { proc.foo.2 push.0 push.1 - exec.u64::checked_add + exec.u64::wrapping_add end"; assert_correct_module_serialization(source, true); } @@ -940,7 +940,7 @@ fn test_ast_module_serde_imports_not_serialized() { proc.foo.2 push.0 push.1 - exec.u64::checked_add + exec.u64::wrapping_add end"; assert_correct_module_serialization(source, false); } diff --git a/docs/src/user_docs/assembly/code_organization.md b/docs/src/user_docs/assembly/code_organization.md index bdd62cdc94..8091162062 100644 --- a/docs/src/user_docs/assembly/code_organization.md +++ b/docs/src/user_docs/assembly/code_organization.md @@ -107,7 +107,7 @@ use.std::math::u64 begin push.1.0 push.2.0 - exec.u64::checked_add + exec.u64::wrapping_add end ``` In the above example we import `std::math::u64` module from the [standard library](../stdlib/main.md). We then execute a program which pushes two 64-bit integers onto the stack, and then invokes a 64-bit addition procedure from the imported module. @@ -156,7 +156,7 @@ const.ADDR_1=3 begin push.CONSTANT_1.CONSTANT_2 - exec.u64::checked_add + exec.u64::wrapping_add mem_store.ADDR_1 end diff --git a/docs/src/user_docs/stdlib/math/u64.md b/docs/src/user_docs/stdlib/math/u64.md index 8cb6fe1775..a607e3e2df 100644 --- a/docs/src/user_docs/stdlib/math/u64.md +++ b/docs/src/user_docs/stdlib/math/u64.md @@ -10,60 +10,43 @@ All procedures assume that an unsigned 64-bit integer (u64) is encoded using two [a_hi, a_lo, ... ] ``` -Procedures which check whether the input values are encoded correctly are designated with `checked` prefix. For example, `checked_add` would fail if any of the top 4 elements on the stack contains a value greater than $2^{32} - 1$. In contrast, `wrapping_add` and `overflowing_add` would not perform these checks, and therefore, if any of the top 4 stack elements is greater than $2^{32} - 1$, the operation will not fail but rather will produce an undefined result. Thus, when using versions of procedures which are not checked, it is important to be certain that input values are 32-bit limbs encoding valid u64 values. +It is important to be certain that procedures designated with `wrapping` and `overflowing` prefixes would not perform the check whether the input values are 32-bit limbs encoding valid u64 values. For example, `wrapping_add` and `overflowing_add` would not perform these checks, and therefore, if any of the top 4 stack elements is greater than $2^{32} - 1$, the operation will not fail but rather will produce an undefined result. ## Arithmetic operations | Procedure | Description | | ------------------ | ------------- | -| checked_add | Performs addition of two unsigned 64-bit integers and fails if the result would overflow.
The input values are expected to be represented using 32-bit limbs, and the procedure will fail if they are not.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = (a + b) % 2^64 | -| overflowing_add | Performs addition of two unsigned 64-bit integers preserving the overflow.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [overflow_flag, c_hi, c_lo, ...], where c = (a + b) % 2^64 | -| wrapping_add | Performs addition of two unsigned 64-bit integers discarding the overflow.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = (a + b) % 2^64 | -| checked_sub | Performs subtraction of two unsigned 64-bit integers and fails if the result would underflow.
The input values are expected to be represented using 32-bit limbs, and the procedure will fail if they are not.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = (a - b) % 2^64 | -| overflowing_sub | Performs subtraction of two unsigned 64-bit integers preserving the overflow.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [underflow_flag, c_hi, c_lo, ...], where c = (a - b) % 2^64 | -| wrapping_sub | Performs subtraction of two unsigned 64-bit integers discarding the overflow.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = (a - b) % 2^64 | -| checked_mul | Performs multiplication of two unsigned 64-bit integers and fails if the result would overflow.
The input values are expected to be represented using 32-bit limbs, and the procedure will fail if they are not.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = (a * b) % 2^64 | -| overflowing_mul | Performs multiplication of two unsigned 64-bit integers preserving the overflow.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi_hi, c_hi_lo, c_lo_hi, c_lo_lo, ...], where c = (a * b) % 2^64| -| wrapping_mul | Performs multiplication of two unsigned 64-bit integers discarding the overflow.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = (a * b) % 2^64 | -| checked_div | Performs division of two unsigned 64-bit integers discarding the remainder.
The input values are expected to be represented using 32-bit limbs, and the procedure will fail if they are not.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a // b | -| unchecked_div | Performs division of two unsigned 64-bit integers discarding the remainder.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a // b | -| checked_mod | Performs modulo operation of two unsigned 64-bit integers.
The input values are expected to be represented using 32-bit limbs, and the procedure will fail if they are not.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a % b | -| unchecked_mod | Performs modulo operation of two unsigned 64-bit integers.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a % b | -| checked_divmod | Performs divmod operation of two unsigned 64-bit integers.
The input values are expected to be represented using 32-bit limbs, and the procedure will fail if they are not.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [r_hi, r_lo, q_hi, q_lo ...], where r = a % b, q = a // b | -| unchecked_divmod | Performs divmod operation of two unsigned 64-bit integers.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [r_hi, r_lo, q_hi, q_lo ...], where r = a % b, q = a // b | +| overflowing_add | Performs addition of two unsigned 64-bit integers preserving the overflow.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [overflow_flag, c_hi, c_lo, ...], where c = (a + b) % 2^64
This takes 6 cycles.| +| wrapping_add | Performs addition of two unsigned 64-bit integers discarding the overflow.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = (a + b) % 2^64
This takes 7 cycles.| +| overflowing_sub | Performs subtraction of two unsigned 64-bit integers preserving the overflow.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [underflow_flag, c_hi, c_lo, ...], where c = (a - b) % 2^64
This takes 11 cycles. | +| wrapping_sub | Performs subtraction of two unsigned 64-bit integers discarding the overflow.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = (a - b) % 2^64
This takes 10 cycles. | +| overflowing_mul | Performs multiplication of two unsigned 64-bit integers preserving the overflow.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi_hi, c_hi_lo, c_lo_hi, c_lo_lo, ...], where c = (a * b) % 2^64
This takes 18 cycles.| +| wrapping_mul | Performs multiplication of two unsigned 64-bit integers discarding the overflow.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = (a * b) % 2^64
This takes 11 cycles. | +| div | Performs division of two unsigned 64-bit integers discarding the remainder.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a // b
This takes 54 cycles. | +| mod | Performs modulo operation of two unsigned 64-bit integers.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a % b
This takes 54 cycles. | +| divmod | Performs divmod operation of two unsigned 64-bit integers.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [r_hi, r_lo, q_hi, q_lo ...], where r = a % b, q = a // b
This takes 54 cycles. | ## Comparison operations | Procedure | Description | | ------------------ | ------------- | -| checked_lt | Performs less-than comparison of two unsigned 64-bit integers.
The input values are expected to be represented using 32-bit limbs, and the procedure will fail if they are not.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a < b, and 0 otherwise. | -| unchecked_lt | Performs less-than comparison of two unsigned 64-bit integers.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a < b, and 0 otherwise. | -| checked_gt | Performs greater-than comparison of two unsigned 64-bit integers.
The input values are expected to be represented using 32-bit limbs, and the procedure will fail if they are not.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a > b, and 0 otherwise. | -| unchecked_gt | Performs greater-than comparison of two unsigned 64-bit integers.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a > b, and 0 otherwise.
This takes 11 cycles. | -| checked_lte | Performs less-than-or-equal comparison of two unsigned 64-bit integers.
The input values are expected to be represented using 32-bit limbs, and the procedure will fail if they are not.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a <= b, and 0 otherwise. | -| unchecked_lte | Performs less-than-or-equal comparison of two unsigned 64-bit integers.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a <= b, and 0 otherwise. | -| checked_gte | Performs greater-than-or-equal comparison of two unsigned 64-bit integers.
The input values are expected to be represented using 32-bit limbs, and the procedure will fail if they are not.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a >= b, and 0 otherwise. | -| unchecked_gte | Performs greater-than-or-equal comparison of two unsigned 64-bit integers.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a >= b, and 0 otherwise. | -| checked_eq | Performs equality comparison of two unsigned 64-bit integers.
The input values are expected to be represented using 32-bit limbs, and the procedure will fail if they are not.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a == b, and 0 otherwise. | -| unchecked_eq | Performs equality comparison of two unsigned 64-bit integers.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a == b, and 0 otherwise. | -| checked_neq | Performs inequality comparison of two unsigned 64-bit integers.
The input values are expected to be represented using 32-bit limbs, and the procedure will fail if they are not.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a != b, and 0 otherwise. | -| unchecked_neq | Performs inequality comparison of two unsigned 64-bit integers.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a != b, and 0 otherwise. | -| checked_eqz | Performs comparison to zero of an unsigned 64-bit integer.
The input value is assumed to be represented using 32-bit limbs, fails if it is not.
The stack transition looks as follows:
[a_hi, a_lo, ...] -> [c, ...], where c = 1 when a == 0, and 0 otherwise. | -| unchecked_eqz | Performs comparison to zero of an unsigned 64-bit integer.
The input value is assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[a_hi, a_lo, ...] -> [c, ...], where c = 1 when a == 0, and 0 otherwise. | -| checked_min | Compares two unsigned 64-bit integers and drop the larger one from the stack.
The input values are expected to be represented using 32-bit limbs, and the procedure will fail if they are not.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a when a < b, and b otherwise. | -| unchecked_min | Compares two unsigned 64-bit integers and drop the larger one from the stack.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a when a < b, and b otherwise. | -| checked_max | Compares two unsigned 64-bit integers and drop the smaller one from the stack.
The input values are expected to be represented using 32-bit limbs, and the procedure will fail if they are not.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a when a > b, and b otherwise. | -| unchecked_max | Compares two unsigned 64-bit integers and drop the smaller one from the stack.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a when a > b, and b otherwise. | +| lt | Performs less-than comparison of two unsigned 64-bit integers.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a < b, and 0 otherwise.
This takes 11 cycles. | +| gt | Performs greater-than comparison of two unsigned 64-bit integers.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a > b, and 0 otherwise.
This takes 11 cycles. | +| lte | Performs less-than-or-equal comparison of two unsigned 64-bit integers.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a <= b, and 0 otherwise.
This takes 12 cycles. | +| gte | Performs greater-than-or-equal comparison of two unsigned 64-bit integers.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a >= b, and 0 otherwise.
This takes 12 cycles. | +| eq | Performs equality comparison of two unsigned 64-bit integers.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a == b, and 0 otherwise.
This takes 6 cycles. | +| neq | Performs inequality comparison of two unsigned 64-bit integers.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a != b, and 0 otherwise.
This takes 6 cycles. | +| eqz | Performs comparison to zero of an unsigned 64-bit integer.
The input value is assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[a_hi, a_lo, ...] -> [c, ...], where c = 1 when a == 0, and 0 otherwise.
This takes 4 cycles. | +| min | Compares two unsigned 64-bit integers and drop the larger one from the stack.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a when a < b, and b otherwise.
This takes 23 cycles. | +| max | Compares two unsigned 64-bit integers and drop the smaller one from the stack.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a when a > b, and b otherwise.
This takes 23 cycles. | ## Bitwise operations | Procedure | Description | | ----------- | ------------- | -| checked_and | Performs bitwise AND of two unsigned 64-bit integers.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a AND b. | -| checked_or | Performs bitwise OR of two unsigned 64-bit integers.
The input values are expected to be represented using 32-bit limbs, and the procedure will fail if they are not.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a OR b. | -| checked_xor | Performs bitwise XOR of two unsigned 64-bit integers.
The input values are expected to be represented using 32-bit limbs, and the procedure will fail if they are not.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a XOR b. | -| overflowing_shl | Performs left shift of one unsigned 64-bit integer preserving the overflow and
using the pow2 operation.
The input value to be shifted is assumed to be represented using 32-bit limbs.
The shift value should be in the range [0, 64), otherwise it will result in an error.
The stack transition looks as follows:
[b, a_hi, a_lo, ...] -> [d_hi, d_lo, c_hi, c_lo, ...], where (d,c) = a << b,
which d contains the bits shifted out.
This takes 35 cycles. | -| unchecked_shl | Performs left shift of one unsigned 64-bit integer using the pow2 operation.
The input value to be shifted is assumed to be represented using 32-bit limbs.
The shift value should be in the range [0, 64), otherwise it will result in an error.
The stack transition looks as follows:
[b, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a << b mod 2^64.
This takes 28 cycles. | -| overflowing_shr | Performs right shift of one unsigned 64-bit integer preserving the overflow and
using the pow2 operation.
The input value to be shifted is assumed to be represented using 32-bit limbs.
The shift value should be in the range [0, 64), otherwise it will result in an error.
The stack transition looks as follows:
[b, a_hi, a_lo, ...] -> [d_hi, d_lo, c_hi, c_lo, ...], where c = a >> b, d = a << (64 - b).
This takes 94 cycles. | -| unchecked_shr | Performs right shift of one unsigned 64-bit integer using the pow2 operation.
The input value to be shifted is assumed to be represented using 32-bit limbs.
The shift value should be in the range [0, 64), otherwise it will result in an error.
The stack transition looks as follows:
[b, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a >> b.
This takes 44 cycles. | -| unchecked_rotl | Performs left rotation of one unsigned 64-bit integer using the pow2 operation.
The input value to be shifted is assumed to be represented using 32-bit limbs.
The shift value should be in the range [0, 64), otherwise it will result in an error.
The stack transition looks as follows:
[b, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a << b mod 2^64.
This takes 35 cycles. | -| unchecked_rotr | Performs right rotation of one unsigned 64-bit integer using the pow2 operation.
The input value to be shifted is assumed to be represented using 32-bit limbs.
The shift value should be in the range [0, 64), otherwise it will result in an error.
The stack transition looks as follows:
[b, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a << b mod 2^64.
This takes 40 cycles. | +| and | Performs bitwise AND of two unsigned 64-bit integers.
The input values are assumed to be represented using 32-bit limbs, but this is not checked.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a AND b.
This takes 6 cycles. | +| or | Performs bitwise OR of two unsigned 64-bit integers.
The input values are expected to be represented using 32-bit limbs, and the procedure will fail if they are not.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a OR b.
This takes 16 cycles. | +| xor | Performs bitwise XOR of two unsigned 64-bit integers.
The input values are expected to be represented using 32-bit limbs, and the procedure will fail if they are not.
The stack transition looks as follows:
[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a XOR b.
This takes 6 cycles. | +| shl | Performs left shift of one unsigned 64-bit integer using the pow2 operation.
The input value to be shifted is assumed to be represented using 32-bit limbs.
The shift value should be in the range [0, 64), otherwise it will result in an error.
The stack transition looks as follows:
[b, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a << b mod 2^64.
This takes 28 cycles.| +| shr | Performs right shift of one unsigned 64-bit integer using the pow2 operation.
The input value to be shifted is assumed to be represented using 32-bit limbs.
The shift value should be in the range [0, 64), otherwise it will result in an error.
The stack transition looks as follows:
[b, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a >> b.
This takes 44 cycles. | +| rotl | Performs left rotation of one unsigned 64-bit integer using the pow2 operation.
The input value to be shifted is assumed to be represented using 32-bit limbs.
The shift value should be in the range [0, 64), otherwise it will result in an error.
The stack transition looks as follows:
[b, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a << b mod 2^64.
This takes 35 cycles. | +| rotr | Performs right rotation of one unsigned 64-bit integer using the pow2 operation.
The input value to be shifted is assumed to be represented using 32-bit limbs.
The shift value should be in the range [0, 64), otherwise it will result in an error.
The stack transition looks as follows:
[b, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a << b mod 2^64.
This takes 40 cycles. | diff --git a/stdlib/asm/math/u64.masm b/stdlib/asm/math/u64.masm index 19c6d5a3ce..fa2dd84b7f 100644 --- a/stdlib/asm/math/u64.masm +++ b/stdlib/asm/math/u64.masm @@ -2,6 +2,7 @@ #! Asserts that both values at the top of the stack are u64 values. #! The input values are assumed to be represented using 32 bit limbs, fails if they are not. +#! This takes 6 cycles. proc.u32assert4 u32assert2 movup.3 @@ -17,6 +18,7 @@ end #! The input values are assumed to be represented using 32 bit limbs, but this is not checked. #! Stack transition looks as follows: #! [b_hi, b_lo, a_hi, a_lo, ...] -> [overflowing_flag, c_hi, c_lo, ...], where c = (a + b) % 2^64 +#! This takes 6 cycles. export.overflowing_add swap movup.3 @@ -30,34 +32,19 @@ end #! The input values are assumed to be represented using 32 bit limbs, but this is not checked. #! Stack transition looks as follows: #! [b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = (a + b) % 2^64 +#! This takes 7 cycles. export.wrapping_add exec.overflowing_add drop end -#! Performs addition of two unsigned 64 bit integers, fails when overflowing. -#! The input values are assumed to be represented using 32 bit limbs, fails if they are not. -#! Stack transition looks as follows: -#! [b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = (a + b) % 2^64 -export.checked_add - swap - movup.3 - u32assert2 - u32overflowing_add - movup.3 - movup.3 - u32assert2 - u32overflowing_add3 - eq.0 - assert -end - # ===== SUBTRACTION =============================================================================== #! Performs subtraction of two unsigned 64 bit integers discarding the overflow. #! The input values are assumed to be represented using 32 bit limbs, but this is not checked. #! Stack transition looks as follows: #! [b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = (a - b) % 2^64 +#! This takes 10 cycles. export.wrapping_sub movup.3 movup.2 @@ -71,31 +58,11 @@ export.wrapping_sub drop end -#! Performs subtraction of two unsigned 64 bit integers, fails when underflowing. -#! The input values are assumed to be represented using 32 bit limbs, fails if they are not. -#! Stack transition looks as follows: -#! [b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = (a - b) % 2^64 -export.checked_sub - movup.3 - movup.2 - u32assert2 - u32overflowing_sub - movup.3 - movup.3 - u32assert2 - u32overflowing_sub - eq.0 - assert - swap - u32overflowing_sub - eq.0 - assert -end - #! Performs subtraction of two unsigned 64 bit integers preserving the overflow. #! The input values are assumed to be represented using 32 bit limbs, but this is not checked. #! Stack transition looks as follows: #! [b_hi, b_lo, a_hi, a_lo, ...] -> [underflowing_flag, c_hi, c_lo, ...], where c = (a - b) % 2^64 +#! This takes 11 cycles. export.overflowing_sub movup.3 movup.2 @@ -116,6 +83,7 @@ end #! The input values are assumed to be represented using 32 bit limbs, but this is not checked. #! Stack transition looks as follows: #! [b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = (a * b) % 2^64 +#! This takes 11 cycles. export.wrapping_mul dup.3 dup.2 @@ -156,67 +124,19 @@ export.overflowing_mul add end -#! Performs multiplication of two unsigned 64 bit integers, fails when overflowing. -#! The input values are assumed to be represented using 32 bit limbs, fails if they are not. -#! Stack transition looks as follows: -#! [b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = (a * b) % 2^64 -export.checked_mul - dup.3 - dup.2 - u32assert2 # make sure lower limbs of operands are 32-bit - u32overflowing_mul - dup.4 - movup.4 - u32overflowing_madd - swap - movup.5 - dup.4 - u32overflowing_madd - movup.5 - movup.5 - u32assert2 # make sure higher limbs of operands are 32-bit - u32overflowing_madd - movup.3 - movup.2 - u32overflowing_add - add - add - eq.0 - assert -end - # ===== COMPARISONS =============================================================================== #! Performs less-than comparison of two unsigned 64 bit integers. #! The input values are assumed to be represented using 32 bit limbs, but this is not checked. #! Stack transition looks as follows: #! [b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a < b, and 0 otherwise. -export.unchecked_lt - movup.3 - movup.2 - u32overflowing_sub - movdn.3 - drop - u32overflowing_sub - swap - eq.0 - movup.2 - and - or -end - -#! Performs less-than comparison of two unsigned 64 bit integers. -#! The input values are assumed to be represented using 32 bit limbs, fails if they are not. -#! Stack transition looks as follows: -#! [b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a < b, and 0 otherwise. -export.checked_lt +#! This takes 11 cycles. +export.lt movup.3 movup.2 - u32assert2 u32overflowing_sub movdn.3 drop - u32assert2 u32overflowing_sub swap eq.0 @@ -230,31 +150,11 @@ end #! Stack transition looks as follows: #! [b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a > b, and 0 otherwise. #! This takes 11 cycles. -export.unchecked_gt - movup.2 - u32overflowing_sub - movup.2 - movup.3 - u32overflowing_sub - swap - drop - movup.2 - eq.0 - and - or -end - -#! Performs greater-than comparison of two unsigned 64 bit integers. -#! The input values are assumed to be represented using 32 bit limbs, fails if they are not. -#! Stack transition looks as follows: -#! [b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a > b, and 0 otherwise. -export.checked_gt +export.gt movup.2 - u32assert2 u32overflowing_sub movup.2 movup.3 - u32assert2 u32overflowing_sub swap drop @@ -268,17 +168,9 @@ end #! The input values are assumed to be represented using 32 bit limbs, but this is not checked. #! Stack transition looks as follows: #! [b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a <= b, and 0 otherwise. -export.unchecked_lte - exec.unchecked_gt - not -end - -#! Performs less-than-or-equal comparison of two unsigned 64 bit integers. -#! The input values are assumed to be represented using 32 bit limbs, fails if they are not. -#! Stack transition looks as follows: -#! [b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a <= b, and 0 otherwise. -export.checked_lte - exec.checked_gt +#! This takes 12 cycles. +export.lte + exec.gt not end @@ -286,17 +178,9 @@ end #! The input values are assumed to be represented using 32 bit limbs, but this is not checked. #! Stack transition looks as follows: #! [b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a >= b, and 0 otherwise. -export.unchecked_gte - exec.unchecked_lt - not -end - -#! Performs greater-than-or-equal comparison of two unsigned 64 bit integers. -#! The input values are assumed to be represented using 32 bit limbs, fails if they are not. -#! Stack transition looks as follows: -#! [b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a >= b, and 0 otherwise. -export.checked_gte - exec.checked_lt +#! This takes 12 cycles. +export.gte + exec.lt not end @@ -304,7 +188,8 @@ end #! The input values are assumed to be represented using 32 bit limbs, but this is not checked. #! Stack transition looks as follows: #! [b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a == b, and 0 otherwise. -export.unchecked_eq +#! This takes 6 cycles. +export.eq movup.2 eq swap @@ -313,24 +198,12 @@ export.unchecked_eq and end -#! Performs equality comparison of two unsigned 64 bit integers. -#! The input values are assumed to be represented using 32 bit limbs, fails if they are not. -#! Stack transition looks as follows: -#! [b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a == b, and 0 otherwise. -export.checked_eq - movup.2 - u32assert2 eq - swap - movup.2 - u32assert2 eq - and -end - #! Performs inequality comparison of two unsigned 64 bit integers. #! The input values are assumed to be represented using 32 bit limbs, but this is not checked. #! Stack transition looks as follows: #! [b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a != b, and 0 otherwise. -export.unchecked_neq +#! This takes 6 cycles. +export.neq movup.2 neq swap @@ -339,32 +212,12 @@ export.unchecked_neq or end -#! Performs inequality comparison of two unsigned 64 bit integers. -#! The input values are assumed to be represented using 32 bit limbs, fails if they are not. -#! Stack transition looks as follows: -#! [b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a == b, and 0 otherwise. -export.checked_neq - exec.checked_eq - not -end - #! Performs comparison to zero of an unsigned 64 bit integer. #! The input value is assumed to be represented using 32 bit limbs, but this is not checked. #! Stack transition looks as follows: #! [a_hi, a_lo, ...] -> [c, ...], where c = 1 when a == 0, and 0 otherwise. -export.unchecked_eqz - eq.0 - swap - eq.0 - and -end - -#! Performs comparison to zero of an unsigned 64 bit integer. -#! The input value is assumed to be represented using 32 bit limbs, fails if it is not. -#! Stack transition looks as follows: -#! [a_hi, a_lo, ...] -> [c, ...], where c = 1 when a == 0, and 0 otherwise. -export.checked_eqz - u32assert2 +#! This takes 4 cycles. +export.eqz eq.0 swap eq.0 @@ -375,9 +228,10 @@ end #! The input values are assumed to be represented using 32 bit limbs, but this is not checked. #! Stack transition looks as follows: #! [b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a when a < b, and b otherwise. -export.unchecked_min +#! This takes 23 cycles. +export.min dupw - exec.unchecked_gt + exec.gt movup.4 movup.3 dup.2 @@ -386,22 +240,14 @@ export.unchecked_min cdrop end -#! Compares two unsigned 64 bit integers and drop the larger one from the stack. -#! The input values are assumed to be represented using 32 bit limbs, fails if they are not. -#! Stack transition looks as follows: -#! [b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a when a < b, and b otherwise. -export.checked_min - exec.u32assert4 - exec.unchecked_min -end - #! Compares two unsigned 64 bit integers and drop the smaller one from the stack. #! The input values are assumed to be represented using 32 bit limbs, but this is not checked. #! Stack transition looks as follows: #! [b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a when a > b, and b otherwise. -export.unchecked_max +#! This takes 23 cycles. +export.max dupw - exec.unchecked_lt + exec.lt movup.4 movup.3 dup.2 @@ -410,23 +256,14 @@ export.unchecked_max cdrop end -#! Compares two unsigned 64 bit integers and drop the smaller one from the stack. -#! The input values are assumed to be represented using 32 bit limbs, fails if they are not. -#! Stack transition looks as follows: -#! [b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a when a > b, and b otherwise. -export.checked_max - exec.u32assert4 - exec.unchecked_max -end - - # ===== DIVISION ================================================================================== #! Performs division of two unsigned 64 bit integers discarding the remainder. #! The input values are assumed to be represented using 32 bit limbs, but this is not checked. #! Stack transition looks as follows: #! [b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a // b -export.unchecked_div +#! This takes 54 cycles. +export.div adv.push_u64div # push the quotient and the remainder onto the advice stack adv_push.2 # pop the quotient from the advice stack and assert it consists of @@ -458,7 +295,7 @@ export.unchecked_div movup.7 # the divisor dup.3 dup.3 - exec.unchecked_gt + exec.gt assert swap # add remainder to the previous result; this also consumes the remainder @@ -476,22 +313,14 @@ export.unchecked_div assert_eq # quotient remains on the stack end -#! Performs division of two unsigned 64 bit integers discarding the remainder. -#! The input values are assumed to be represented using 32 bit limbs, fails if they are not. -#! Stack transition looks as follows: -#! [b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a // b -export.checked_div - exec.u32assert4 - exec.unchecked_div -end - # ===== MODULO OPERATION ========================================================================== #! Performs modulo operation of two unsigned 64 bit integers. #! The input values are assumed to be represented using 32 bit limbs, but this is not checked. #! Stack transition looks as follows: #! [b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a % b -export.unchecked_mod +#! This takes 54 cycles. +export.mod adv.push_u64div # push the quotient and the remainder onto the advice stack adv_push.2 # pop the quotient from the advice stack and assert it consists of @@ -523,7 +352,7 @@ export.unchecked_mod movup.5 # the divisor dup.3 dup.3 - exec.unchecked_gt + exec.gt assert dup.1 # add remainder to the previous result @@ -541,22 +370,14 @@ export.unchecked_mod assert_eq # remainder remains on the stack end -#! Performs modulo operation of two unsigned 64 bit integers. -#! The input values are assumed to be represented using 32 bit limbs, fails if they are not. -#! Stack transition looks as follows: -#! [b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a % b -export.checked_mod - exec.u32assert4 - exec.unchecked_mod -end - # ===== DIVMOD OPERATION ========================================================================== #! Performs divmod operation of two unsigned 64 bit integers. #! The input values are assumed to be represented using 32 bit limbs, but this is not checked. #! Stack transition looks as follows: #! [b_hi, b_lo, a_hi, a_lo, ...] -> [r_hi, r_lo, q_hi, q_lo ...], where r = a % b, q = a / b -export.unchecked_divmod +#! This takes 54 cycles. +export.divmod adv.push_u64div # push the quotient and the remainder onto the advice stack adv_push.2 # pop the quotient from the advice stack and assert it consists of @@ -588,7 +409,7 @@ export.unchecked_divmod movup.7 # the divisor dup.3 dup.3 - exec.unchecked_gt + exec.gt assert dup.1 # add remainder to the previous result @@ -606,22 +427,14 @@ export.unchecked_divmod assert_eq # remainder remains on the stack end -#! Performs divmod operation of two unsigned 64 bit integers. -#! The input values are assumed to be represented using 32 bit limbs, fails if they are not. -#! Stack transition looks as follows: -#! [b_hi, b_lo, a_hi, a_lo, ...] -> [r_hi, r_lo, q_hi, q_lo ...], where r = a % b, q = a / b -export.checked_divmod - exec.u32assert4 - exec.unchecked_divmod -end - # ===== BITWISE OPERATIONS ======================================================================== #! Performs bitwise AND of two unsigned 64-bit integers. #! The input values are assumed to be represented using 32 bit limbs, but this is not checked. #! Stack transition looks as follows: #! [b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a AND b. -export.checked_and +#! This takes 6 cycles. +export.and swap movup.3 u32and @@ -634,7 +447,8 @@ end #! The input values are assumed to be represented using 32 bit limbs, fails if they are not. #! Stack transition looks as follows: #! [b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a OR b. -export.checked_or +#! This takes 16 cycles. +export.or swap movup.3 u32or @@ -647,7 +461,8 @@ end #! The input values are assumed to be represented using 32 bit limbs, fails if they are not. #! Stack transition looks as follows: #! [b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a XOR b. -export.checked_xor +#! This takes 6 cycles. +export.xor swap movup.3 u32xor @@ -663,7 +478,7 @@ end #! Stack transition looks as follows: #! [b, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a << b mod 2^64. #! This takes 28 cycles. -export.unchecked_shl +export.shl pow2 u32split exec.wrapping_mul @@ -677,7 +492,7 @@ end #! Stack transition looks as follows: #! [b, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a >> b. #! This takes 44 cycles. -export.unchecked_shr +export.shr pow2 u32split @@ -709,54 +524,6 @@ export.unchecked_shr cswap end -#! Performs left shift of one unsigned 64-bit integer preserving the overflow and -#! using the pow2 operation. -#! The input value to be shifted is assumed to be represented using 32 bit limbs. -#! The shift value should be in the range [0, 64), otherwise it will result in an -#! error. -#! Stack transition looks as follows: -#! [b, a_hi, a_lo, ...] -> [d_hi, d_lo, c_hi, c_lo, ...], where (d,c) = a << b, -#! which d contains the bits shifted out. -#! This takes 35 cycles. -export.overflowing_shl - pow2 - u32split - exec.overflowing_mul -end - -#! Performs right shift of one unsigned 64-bit integer preserving the overflow and -#! using the pow2 operation. -#! The input value to be shifted is assumed to be represented using 32 bit limbs. -#! The shift value should be in the range [0, 64), otherwise it will result in an -#! error. -#! Stack transition looks as follows: -#! [b, a_hi, a_lo, ...] -> [d_hi, d_lo, c_hi, c_lo, ...], where c = a >> b, d = a << (64 - b). -#! This takes 94 cycles. -export.overflowing_shr - push.64 # (64 - b) - dup.1 - sub - - dup.3 # dup [b, a_hi, a_lo] - dup.3 - dup.3 - exec.unchecked_shr # c = a >> b - - movdn.5 # move result [c_hi, c_lo] to be in the format [d_hi, d_lo, c_hi, c_lo, ...] - movdn.5 - - padw # padding positions 0, 1, 2, 3 and 4 to be able to use cdropw - push.0 - - movup.6 # bring and b - eq.0 - cdropw # if b is 0, swap the positions 0, 1, 2 and 3 with 0, (64 - b), a_hi, a_lo - # regardless of this condition, drop 0, 1, 2 and 3 - drop # drop the last added 0 or dup b to keep the format [b, a_hi, a_lo, ....] - - exec.unchecked_shl # d = a << (64 - b) -end - #! Performs left rotation of one unsigned 64-bit integer using the pow2 operation. #! The input value to be shifted is assumed to be represented using 32 bit limbs. #! The shift value should be in the range [0, 64), otherwise it will result in an @@ -764,7 +531,7 @@ end #! Stack transition looks as follows: #! [b, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a << b mod 2^64. #! This takes 35 cycles. -export.unchecked_rotl +export.rotl push.31 dup.1 u32overflowing_sub @@ -802,7 +569,7 @@ end #! Stack transition looks as follows: #! [b, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a << b mod 2^64. #! This takes 40 cycles. -export.unchecked_rotr +export.rotr push.31 dup.1 u32overflowing_sub diff --git a/stdlib/docs/math/u64.md b/stdlib/docs/math/u64.md index 9745204e41..1db059cdd8 100644 --- a/stdlib/docs/math/u64.md +++ b/stdlib/docs/math/u64.md @@ -2,45 +2,28 @@ ## std::math::u64 | Procedure | Description | | ----------- | ------------- | -| overflowing_add | Performs addition of two unsigned 64 bit integers preserving the overflow.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [overflowing_flag, c_hi, c_lo, ...], where c = (a + b) % 2^64 | -| wrapping_add | Performs addition of two unsigned 64 bit integers discarding the overflow.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = (a + b) % 2^64 | -| checked_add | Performs addition of two unsigned 64 bit integers, fails when overflowing.

The input values are assumed to be represented using 32 bit limbs, fails if they are not.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = (a + b) % 2^64 | -| wrapping_sub | Performs subtraction of two unsigned 64 bit integers discarding the overflow.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = (a - b) % 2^64 | -| checked_sub | Performs subtraction of two unsigned 64 bit integers, fails when underflowing.

The input values are assumed to be represented using 32 bit limbs, fails if they are not.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = (a - b) % 2^64 | -| overflowing_sub | Performs subtraction of two unsigned 64 bit integers preserving the overflow.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [underflowing_flag, c_hi, c_lo, ...], where c = (a - b) % 2^64 | -| wrapping_mul | Performs multiplication of two unsigned 64 bit integers discarding the overflow.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = (a * b) % 2^64 | +| overflowing_add | Performs addition of two unsigned 64 bit integers preserving the overflow.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [overflowing_flag, c_hi, c_lo, ...], where c = (a + b) % 2^64

This takes 6 cycles. | +| wrapping_add | Performs addition of two unsigned 64 bit integers discarding the overflow.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = (a + b) % 2^64

This takes 7 cycles. | +| wrapping_sub | Performs subtraction of two unsigned 64 bit integers discarding the overflow.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = (a - b) % 2^64

This takes 10 cycles. | +| overflowing_sub | Performs subtraction of two unsigned 64 bit integers preserving the overflow.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [underflowing_flag, c_hi, c_lo, ...], where c = (a - b) % 2^64

This takes 11 cycles. | +| wrapping_mul | Performs multiplication of two unsigned 64 bit integers discarding the overflow.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = (a * b) % 2^64

This takes 11 cycles. | | overflowing_mul | Performs multiplication of two unsigned 64 bit integers preserving the overflow.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_mid_hi, c_mid_lo, c_lo, ...], where c = (a * b) % 2^64

This takes 18 cycles. | -| checked_mul | Performs multiplication of two unsigned 64 bit integers, fails when overflowing.

The input values are assumed to be represented using 32 bit limbs, fails if they are not.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = (a * b) % 2^64 | -| unchecked_lt | Performs less-than comparison of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a < b, and 0 otherwise. | -| checked_lt | Performs less-than comparison of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, fails if they are not.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a < b, and 0 otherwise. | -| unchecked_gt | Performs greater-than comparison of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a > b, and 0 otherwise.

This takes 11 cycles. | -| checked_gt | Performs greater-than comparison of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, fails if they are not.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a > b, and 0 otherwise. | -| unchecked_lte | Performs less-than-or-equal comparison of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a <= b, and 0 otherwise. | -| checked_lte | Performs less-than-or-equal comparison of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, fails if they are not.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a <= b, and 0 otherwise. | -| unchecked_gte | Performs greater-than-or-equal comparison of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a >= b, and 0 otherwise. | -| checked_gte | Performs greater-than-or-equal comparison of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, fails if they are not.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a >= b, and 0 otherwise. | -| unchecked_eq | Performs equality comparison of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a == b, and 0 otherwise. | -| checked_eq | Performs equality comparison of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, fails if they are not.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a == b, and 0 otherwise. | -| unchecked_neq | Performs inequality comparison of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a != b, and 0 otherwise. | -| checked_neq | Performs inequality comparison of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, fails if they are not.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a == b, and 0 otherwise. | -| unchecked_eqz | Performs comparison to zero of an unsigned 64 bit integer.

The input value is assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[a_hi, a_lo, ...] -> [c, ...], where c = 1 when a == 0, and 0 otherwise. | -| checked_eqz | Performs comparison to zero of an unsigned 64 bit integer.

The input value is assumed to be represented using 32 bit limbs, fails if it is not.

Stack transition looks as follows:

[a_hi, a_lo, ...] -> [c, ...], where c = 1 when a == 0, and 0 otherwise. | -| unchecked_min | Compares two unsigned 64 bit integers and drop the larger one from the stack.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a when a < b, and b otherwise. | -| checked_min | Compares two unsigned 64 bit integers and drop the larger one from the stack.

The input values are assumed to be represented using 32 bit limbs, fails if they are not.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a when a < b, and b otherwise. | -| unchecked_max | Compares two unsigned 64 bit integers and drop the smaller one from the stack.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a when a > b, and b otherwise. | -| checked_max | Compares two unsigned 64 bit integers and drop the smaller one from the stack.

The input values are assumed to be represented using 32 bit limbs, fails if they are not.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a when a > b, and b otherwise. | -| unchecked_div | Performs division of two unsigned 64 bit integers discarding the remainder.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a // b | -| checked_div | Performs division of two unsigned 64 bit integers discarding the remainder.

The input values are assumed to be represented using 32 bit limbs, fails if they are not.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a // b | -| unchecked_mod | Performs modulo operation of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a % b | -| checked_mod | Performs modulo operation of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, fails if they are not.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a % b | -| unchecked_divmod | Performs divmod operation of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [r_hi, r_lo, q_hi, q_lo ...], where r = a % b, q = a / b | -| checked_divmod | Performs divmod operation of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, fails if they are not.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [r_hi, r_lo, q_hi, q_lo ...], where r = a % b, q = a / b | -| checked_and | Performs bitwise AND of two unsigned 64-bit integers.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a AND b. | -| checked_or | Performs bitwise OR of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, fails if they are not.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a OR b. | -| checked_xor | Performs bitwise XOR of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, fails if they are not.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a XOR b. | -| unchecked_shl | Performs left shift of one unsigned 64-bit integer using the pow2 operation.

The input value to be shifted is assumed to be represented using 32 bit limbs.

The shift value should be in the range [0, 64), otherwise it will result in an

error.

Stack transition looks as follows:

[b, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a << b mod 2^64.

This takes 28 cycles. | -| unchecked_shr | Performs right shift of one unsigned 64-bit integer using the pow2 operation.

The input value to be shifted is assumed to be represented using 32 bit limbs.

The shift value should be in the range [0, 64), otherwise it will result in an

error.

Stack transition looks as follows:

[b, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a >> b.

This takes 44 cycles. | -| overflowing_shl | Performs left shift of one unsigned 64-bit integer preserving the overflow and

using the pow2 operation.

The input value to be shifted is assumed to be represented using 32 bit limbs.

The shift value should be in the range [0, 64), otherwise it will result in an

error.

Stack transition looks as follows:

[b, a_hi, a_lo, ...] -> [d_hi, d_lo, c_hi, c_lo, ...], where (d,c) = a << b,

which d contains the bits shifted out.

This takes 35 cycles. | -| overflowing_shr | Performs right shift of one unsigned 64-bit integer preserving the overflow and

using the pow2 operation.

The input value to be shifted is assumed to be represented using 32 bit limbs.

The shift value should be in the range [0, 64), otherwise it will result in an

error.

Stack transition looks as follows:

[b, a_hi, a_lo, ...] -> [d_hi, d_lo, c_hi, c_lo, ...], where c = a >> b, d = a << (64 - b).

This takes 94 cycles. | -| unchecked_rotl | Performs left rotation of one unsigned 64-bit integer using the pow2 operation.

The input value to be shifted is assumed to be represented using 32 bit limbs.

The shift value should be in the range [0, 64), otherwise it will result in an

error.

Stack transition looks as follows:

[b, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a << b mod 2^64.

This takes 35 cycles. | -| unchecked_rotr | Performs right rotation of one unsigned 64-bit integer using the pow2 operation.

The input value to be shifted is assumed to be represented using 32 bit limbs.

The shift value should be in the range [0, 64), otherwise it will result in an

error.

Stack transition looks as follows:

[b, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a << b mod 2^64.

This takes 40 cycles. | +| lt | Performs less-than comparison of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a < b, and 0 otherwise.

This takes 11 cycles. | +| gt | Performs greater-than comparison of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a > b, and 0 otherwise.

This takes 11 cycles. | +| lte | Performs less-than-or-equal comparison of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a <= b, and 0 otherwise.

This takes 12 cycles. | +| gte | Performs greater-than-or-equal comparison of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a >= b, and 0 otherwise.

This takes 12 cycles. | +| eq | Performs equality comparison of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a == b, and 0 otherwise.

This takes 6 cycles. | +| neq | Performs inequality comparison of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c, ...], where c = 1 when a != b, and 0 otherwise.

This takes 6 cycles. | +| eqz | Performs comparison to zero of an unsigned 64 bit integer.

The input value is assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[a_hi, a_lo, ...] -> [c, ...], where c = 1 when a == 0, and 0 otherwise.

This takes 4 cycles. | +| min | Compares two unsigned 64 bit integers and drop the larger one from the stack.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a when a < b, and b otherwise.

This takes 23 cycles. | +| max | Compares two unsigned 64 bit integers and drop the smaller one from the stack.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a when a > b, and b otherwise.

This takes 23 cycles. | +| div | Performs division of two unsigned 64 bit integers discarding the remainder.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a // b

This takes 54 cycles. | +| mod | Performs modulo operation of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a % b

This takes 54 cycles. | +| divmod | Performs divmod operation of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [r_hi, r_lo, q_hi, q_lo ...], where r = a % b, q = a / b

This takes 54 cycles. | +| and | Performs bitwise AND of two unsigned 64-bit integers.

The input values are assumed to be represented using 32 bit limbs, but this is not checked.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a AND b.

This takes 6 cycles. | +| or | Performs bitwise OR of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, fails if they are not.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a OR b.

This takes 16 cycles. | +| xor | Performs bitwise XOR of two unsigned 64 bit integers.

The input values are assumed to be represented using 32 bit limbs, fails if they are not.

Stack transition looks as follows:

[b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a XOR b.

This takes 6 cycles. | +| shl | Performs left shift of one unsigned 64-bit integer using the pow2 operation.

The input value to be shifted is assumed to be represented using 32 bit limbs.

The shift value should be in the range [0, 64), otherwise it will result in an

error.

Stack transition looks as follows:

[b, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a << b mod 2^64.

This takes 28 cycles. | +| shr | Performs right shift of one unsigned 64-bit integer using the pow2 operation.

The input value to be shifted is assumed to be represented using 32 bit limbs.

The shift value should be in the range [0, 64), otherwise it will result in an

error.

Stack transition looks as follows:

[b, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a >> b.

This takes 44 cycles. | +| rotl | Performs left rotation of one unsigned 64-bit integer using the pow2 operation.

The input value to be shifted is assumed to be represented using 32 bit limbs.

The shift value should be in the range [0, 64), otherwise it will result in an

error.

Stack transition looks as follows:

[b, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a << b mod 2^64.

This takes 35 cycles. | +| rotr | Performs right rotation of one unsigned 64-bit integer using the pow2 operation.

The input value to be shifted is assumed to be represented using 32 bit limbs.

The shift value should be in the range [0, 64), otherwise it will result in an

error.

Stack transition looks as follows:

[b, a_hi, a_lo, ...] -> [c_hi, c_lo, ...], where c = a << b mod 2^64.

This takes 40 cycles. | diff --git a/stdlib/tests/math/u64_mod.rs b/stdlib/tests/math/u64_mod.rs index 1c5a7e5333..e128467393 100644 --- a/stdlib/tests/math/u64_mod.rs +++ b/stdlib/tests/math/u64_mod.rs @@ -25,58 +25,6 @@ fn wrapping_add() { test.expect_stack(&[c1, c0]); } -#[test] -fn checked_add() { - let source = " - use.std::math::u64 - begin - exec.u64::checked_add - end"; - - // --- simple case ---------------------------------------------------------------------------- - let test = build_test!(source, &[1, 2, 3, 4]); - test.expect_stack(&[6, 4]); - - // --- random values -------------------------------------------------------------------------- - // test using u16 values to ensure there's no overflow so the result is valid - let a0 = rand_value::() as u16 as u64; - let b0 = rand_value::() as u16 as u64; - let a1 = rand_value::() as u16 as u64; - let b1 = rand_value::() as u16 as u64; - let c0 = a0 + b0; - let c1 = a1 + b1; - - let test = build_test!(source, &[a0, a1, b0, b1]); - test.expect_stack(&[c1, c0]); -} - -#[test] -fn checked_add_fail() { - let source = " - use.std::math::u64 - begin - exec.u64::checked_add - end"; - - // result overflow - let a0 = rand_value::() as u32 as u64; - let b0 = rand_value::() as u32 as u64; - let a1 = u32::MAX as u64; - let b1 = u32::MAX as u64; - - let test = build_test!(source, &[a0, a1, b0, b1]); - test.expect_error(TestError::ExecutionError("FailedAssertion")); - - // u32 limb assertion failure - let a0 = rand_value::(); - let b0 = rand_value::(); - let a1 = U32_BOUND; - let b1 = U32_BOUND; - - let test = build_test!(source, &[a0, a1, b0, b1]); - test.expect_error(TestError::ExecutionError("NotU32Value")); -} - #[test] fn overflowing_add() { let source = " @@ -131,61 +79,6 @@ fn wrapping_sub() { test.expect_stack(&[c1, c0]); } -#[test] -fn checked_sub() { - let source = " - use.std::math::u64 - begin - exec.u64::checked_sub - end"; - - // --- simple case ---------------------------------------------------------------------------- - let test = build_test!(source, &[3, 4, 1, 2]); - test.expect_stack(&[2, 2]); - - // --- random values -------------------------------------------------------------------------- - let common = rand_value::(); - let dif = rand_value::() as u16 as u64; - - let a = common + dif; - let b = common; - let c = a - b; - - let (a1, a0) = split_u64(a); - let (b1, b0) = split_u64(b); - let (c1, c0) = split_u64(c); - - let test = build_test!(source, &[a0, a1, b0, b1]); - test.expect_stack(&[c1, c0]); -} - -#[test] -fn checked_sub_fail() { - let source = " - use.std::math::u64 - begin - exec.u64::checked_sub - end"; - - // result underflow - let a0 = rand_value::() as u32 as u64; - let b0 = rand_value::() as u32 as u64; - let a1 = u16::MAX as u64; - let b1 = u32::MAX as u64; - - let test = build_test!(source, &[a0, a1, b0, b1]); - test.expect_error(TestError::ExecutionError("FailedAssertion")); - - // u32 limb assertion failure - let a0 = rand_value::(); - let b0 = rand_value::(); - let a1 = U32_BOUND; - let b1 = U32_BOUND; - - let test = build_test!(source, &[a0, a1, b0, b1]); - test.expect_error(TestError::ExecutionError("NotU32Value")); -} - #[test] fn overflowing_sub() { let a: u64 = rand_value(); @@ -257,75 +150,6 @@ fn wrapping_mul() { test.expect_stack(&[c1, c0]); } -#[test] -fn checked_mul() { - let source = " - use.std::math::u64 - begin - exec.u64::checked_mul - end"; - - // --- simple cases --------------------------------------------------------------------------- - let test = build_test!(source, &[1, 2, 0, 0]); - test.expect_stack(&[0, 0]); - - let test = build_test!(source, &[0, 0, 1, 2]); - test.expect_stack(&[0, 0]); - - let test = build_test!(source, &[5, 1, 1, 0]); - test.expect_stack(&[1, 5]); - - let test = build_test!(source, &[5, 2, 2, 0]); - test.expect_stack(&[4, 10]); - - // --- random values -------------------------------------------------------------------------- - let a0 = rand_value::() as u16 as u64; - let a1 = rand_value::() as u16 as u64; - let b0 = rand_value::() as u16 as u64; - let b1 = 0u64; - let c0 = a0 * b0; - let c1 = a1 * b0; - - let test = build_test!(source, &[a0, a1, b0, b1]); - test.expect_stack(&[c1, c0]); -} - -#[test] -fn checked_mul_fail() { - let source = " - use.std::math::u64 - begin - exec.u64::checked_mul - end"; - - // u32 limb assertion failure - for i in 0..4 { - let mut stack_init = [1, 2, 3, 4]; - stack_init[i] = U32_BOUND; - let test = build_test!(source, &stack_init); - test.expect_error(TestError::ExecutionError("NotU32Value")); - } - - // Higher bits assertion failure (a_hi * b_hi != 0) - - let a0 = rand_value::() as u16 as u64; - let a1 = 2u64; - let b0 = rand_value::() as u16 as u64; - let b1 = 3u64; - - let test = build_test!(source, &[a0, a1, b0, b1]); - test.expect_error(TestError::ExecutionError("FailedAssertion")); - - // result overflow - let a0 = rand_value::() as u32 as u64; - let a1 = u16::MAX as u64 + rand_value::() as u16 as u64; - let b0 = u16::MAX as u64 + rand_value::() as u16 as u64; - let b1 = 0u64; - - let test = build_test!(source, &[a0, a1, b0, b1]); - test.expect_error(TestError::ExecutionError("FailedAssertion")); -} - #[test] fn overflowing_mul() { let source = " @@ -372,7 +196,7 @@ fn unchecked_lt() { let source = " use.std::math::u64 begin - exec.u64::unchecked_lt + exec.u64::lt end"; // a = 0, b = 0 @@ -390,7 +214,7 @@ fn unchecked_lte() { let source = " use.std::math::u64 begin - exec.u64::unchecked_lte + exec.u64::lte end"; // a = 0, b = 0 @@ -418,7 +242,7 @@ fn unchecked_gt() { let source = " use.std::math::u64 begin - exec.u64::unchecked_gt + exec.u64::gt end"; // a = 0, b = 0 @@ -436,7 +260,7 @@ fn unchecked_gte() { let source = " use.std::math::u64 begin - exec.u64::unchecked_gte + exec.u64::gte end"; // a = 0, b = 0 @@ -464,7 +288,7 @@ fn unchecked_min() { let source = " use.std::math::u64 begin - exec.u64::unchecked_min + exec.u64::min end"; // a = 0, b = 0 @@ -483,7 +307,7 @@ fn unchecked_max() { let source = " use.std::math::u64 begin - exec.u64::unchecked_max + exec.u64::max end"; // a = 0, b = 0 @@ -501,7 +325,7 @@ fn unchecked_eq() { let source = " use.std::math::u64 begin - exec.u64::unchecked_eq + exec.u64::eq end"; // a = 0, b = 0 @@ -528,7 +352,7 @@ fn unchecked_neq() { let source = " use.std::math::u64 begin - exec.u64::unchecked_neq + exec.u64::neq end"; // a = 0, b = 0 @@ -555,7 +379,7 @@ fn unchecked_eqz() { let source = " use.std::math::u64 begin - exec.u64::unchecked_eqz + exec.u64::eqz end"; // a = 0 @@ -584,7 +408,7 @@ fn unchecked_div() { let source = " use.std::math::u64 begin - exec.u64::unchecked_div + exec.u64::div end"; let (a1, a0) = split_u64(a); @@ -601,23 +425,6 @@ fn unchecked_div() { test.expect_stack(&[d1, d0]); } -#[test] -fn checked_div_fail() { - let source = " - use.std::math::u64 - begin - exec.u64::checked_div - end"; - - // u32 limb assertion failure - for i in 0..4 { - let mut stack_init = [1, 2, 3, 4]; - stack_init[i] = U32_BOUND; - let test = build_test!(source, &stack_init); - test.expect_error(TestError::ExecutionError("NotU32Value")); - } -} - // MODULO OPERATION // ------------------------------------------------------------------------------------------------ @@ -630,7 +437,7 @@ fn unchecked_mod() { let source = " use.std::math::u64 begin - exec.u64::unchecked_mod + exec.u64::mod end"; let (a1, a0) = split_u64(a); @@ -647,23 +454,6 @@ fn unchecked_mod() { test.expect_stack(&[d1, d0]); } -#[test] -fn checked_mod_fail() { - let source = " - use.std::math::u64 - begin - exec.u64::checked_mod - end"; - - // u32 limb assertion failure - for i in 0..4 { - let mut stack_init = [1, 2, 3, 4]; - stack_init[i] = U32_BOUND; - let test = build_test!(source, &stack_init); - test.expect_error(TestError::ExecutionError("NotU32Value")); - } -} - // DIVMOD OPERATION // ------------------------------------------------------------------------------------------------ @@ -677,7 +467,7 @@ fn unchecked_divmod() { let source = " use.std::math::u64 begin - exec.u64::unchecked_divmod + exec.u64::divmod end"; let (a1, a0) = split_u64(a); @@ -689,23 +479,6 @@ fn unchecked_divmod() { test.expect_stack(&[r1, r0, q1, q0]); } -#[test] -fn checked_divmod_fail() { - let source = " - use.std::math::u64 - begin - exec.u64::checked_divmod - end"; - - // u32 limb assertion failure - for i in 0..4 { - let mut stack_init = [1, 2, 3, 4]; - stack_init[i] = U32_BOUND; - let test = build_test!(source, &stack_init); - test.expect_error(TestError::ExecutionError("NotU32Value")); - } -} - // BITWISE OPERATIONS // ------------------------------------------------------------------------------------------------ @@ -718,7 +491,7 @@ fn checked_and() { let source = " use.std::math::u64 begin - exec.u64::checked_and + exec.u64::and end"; let (a1, a0) = split_u64(a); @@ -740,7 +513,7 @@ fn checked_and_fail() { let source = " use.std::math::u64 begin - exec.u64::checked_and + exec.u64::and end"; let test = build_test!(source, &[a0, a1, b0, b1]); @@ -756,7 +529,7 @@ fn checked_or() { let source = " use.std::math::u64 begin - exec.u64::checked_or + exec.u64::or end"; let (a1, a0) = split_u64(a); @@ -778,7 +551,7 @@ fn checked_or_fail() { let source = " use.std::math::u64 begin - exec.u64::checked_or + exec.u64::or end"; let test = build_test!(source, &[a0, a1, b0, b1]); @@ -794,7 +567,7 @@ fn checked_xor() { let source = " use.std::math::u64 begin - exec.u64::checked_xor + exec.u64::xor end"; let (a1, a0) = split_u64(a); @@ -816,7 +589,7 @@ fn checked_xor_fail() { let source = " use.std::math::u64 begin - exec.u64::checked_xor + exec.u64::xor end"; let test = build_test!(source, &[a0, a1, b0, b1]); @@ -828,7 +601,7 @@ fn unchecked_shl() { let source = " use.std::math::u64 begin - exec.u64::unchecked_shl + exec.u64::shl end"; // shift by 0 @@ -878,7 +651,7 @@ fn unchecked_shr() { let source = " use.std::math::u64 begin - exec.u64::unchecked_shr + exec.u64::shr end"; // shift by 0 @@ -929,141 +702,12 @@ fn unchecked_shr() { build_test!(source, &[5, a0, a1, b as u64]).expect_stack(&[c1, c0, 5]); } -#[test] -fn overflowing_shl() { - let source = " - use.std::math::u64 - begin - exec.u64::overflowing_shl - end"; - - // shl u64 to u128 to avoid overflowing - let shl_to_u128 = |a: u64, b: u32| -> u128 { (a as u128) << b }; - - // shift by 0 - let a: u64 = rand_value(); - let (a1, a0) = split_u64(a); - let b: u32 = 0; - - let c = shl_to_u128(a, b); - let (d1, d0, c1, c0) = split_u128(c); - - build_test!(source, &[5, a0, a1, b as u64]).expect_stack(&[d1, d0, c1, c0, 5]); - - // shift by 31 (max lower limb of b) - let b: u32 = 31; - let c = shl_to_u128(a, b); - let (d1, d0, c1, c0) = split_u128(c); - - build_test!(source, &[5, a0, a1, b as u64]).expect_stack(&[d1, d0, c1, c0, 5]); - - // shift by 32 (min for upper limb of b) - let a = 1_u64; - let (a1, a0) = split_u64(a); - let b: u32 = 32; - let c = shl_to_u128(a, b); - let (d1, d0, c1, c0) = split_u128(c); - - build_test!(source, &[5, a0, a1, b as u64]).expect_stack(&[d1, d0, c1, c0, 5]); - - // shift by 33 - let a = 1_u64; - let (a1, a0) = split_u64(a); - let b: u32 = 33; - let c = shl_to_u128(a, b); - let (d1, d0, c1, c0) = split_u128(c); - - build_test!(source, &[5, a0, a1, b as u64]).expect_stack(&[d1, d0, c1, c0, 5]); - - // shift 64 by 58 - let a = 64_u64; - let (a1, a0) = split_u64(a); - let b: u32 = 58; - let c = shl_to_u128(a, b); - let (d1, d0, c1, c0) = split_u128(c); - - build_test!(source, &[5, a0, a1, b as u64]).expect_stack(&[d1, d0, c1, c0, 5]); -} - -#[test] -fn overflowing_shr() { - let source = " - use.std::math::u64 - begin - exec.u64::overflowing_shr - end"; - - // get bits shifted out and return 0 if b is 0 or 64 - let bits_shifted_out = |a: u64, b: u32| -> u64 { - if b % 64 == 0 { - 0_u64 - } else { - a.wrapping_shl(64 - b) - } - }; - - // shift by 0 - let a: u64 = rand_value(); - let (a1, a0) = split_u64(a); - let b: u32 = 0; - - let c = a.wrapping_shr(b); - let (c1, c0) = split_u64(c); - let d = bits_shifted_out(a, b); - let (d1, d0) = split_u64(d); - - build_test!(source, &[5, a0, a1, b as u64]).expect_stack(&[d1, d0, c1, c0, 5]); - - // shift by 31 (max lower limb of b) - let b: u32 = 31; - - let c = a.wrapping_shr(b); - let (c1, c0) = split_u64(c); - let d = bits_shifted_out(a, b); - let (d1, d0) = split_u64(d); - - build_test!(source, &[5, a0, a1, b as u64]).expect_stack(&[d1, d0, c1, c0, 5]); - - // shift by 32 (min for upper limb of b) - let a = 1_u64; - let (a1, a0) = split_u64(a); - let b: u32 = 32; - let c = a.wrapping_shr(b); - let (c1, c0) = split_u64(c); - let d = bits_shifted_out(a, b); - let (d1, d0) = split_u64(d); - - build_test!(source, &[5, a0, a1, b as u64]).expect_stack(&[d1, d0, c1, c0, 5]); - - // shift by 33 - let a = 1_u64; - let (a1, a0) = split_u64(a); - let b: u32 = 33; - let c = a.wrapping_shr(b); - let (c1, c0) = split_u64(c); - let d = bits_shifted_out(a, b); - let (d1, d0) = split_u64(d); - - build_test!(source, &[5, a0, a1, b as u64]).expect_stack(&[d1, d0, c1, c0, 5]); - - // shift 64 by 58 - let a = 64_u64; - let (a1, a0) = split_u64(a); - let b: u32 = 58; - let c = a.wrapping_shr(b); - let (c1, c0) = split_u64(c); - let d = bits_shifted_out(a, b); - let (d1, d0) = split_u64(d); - - build_test!(source, &[5, a0, a1, b as u64]).expect_stack(&[d1, d0, c1, c0, 5]); -} - #[test] fn unchecked_rotl() { let source = " use.std::math::u64 begin - exec.u64::unchecked_rotl + exec.u64::rotl end"; // shift by 0 @@ -1113,7 +757,7 @@ fn unchecked_rotr() { let source = " use.std::math::u64 begin - exec.u64::unchecked_rotr + exec.u64::rotr end"; // shift by 0 @@ -1172,7 +816,7 @@ proptest! { let source = " use.std::math::u64 begin - exec.u64::unchecked_lt + exec.u64::lt end"; build_test!(source, &[a0, a1, b0, b1]).prop_expect_stack(&[c])?; @@ -1188,7 +832,7 @@ proptest! { let source = " use.std::math::u64 begin - exec.u64::unchecked_gt + exec.u64::gt end"; build_test!(source, &[a0, a1, b0, b1]).prop_expect_stack(&[c])?; @@ -1204,7 +848,7 @@ proptest! { let source = " use.std::math::u64 begin - exec.u64::unchecked_min + exec.u64::min end"; build_test!(source, &[a0, a1, b0, b1]).prop_expect_stack(&[c1, c0])?; @@ -1220,7 +864,7 @@ proptest! { let source = " use.std::math::u64 begin - exec.u64::unchecked_max + exec.u64::max end"; build_test!(source, &[a0, a1, b0, b1]).prop_expect_stack(&[c1, c0])?; @@ -1238,7 +882,7 @@ proptest! { let source = " use.std::math::u64 begin - exec.u64::unchecked_div + exec.u64::div end"; build_test!(source, &[a0, a1, b0, b1]).prop_expect_stack(&[c1, c0])?; @@ -1256,12 +900,13 @@ proptest! { let source = " use.std::math::u64 begin - exec.u64::unchecked_mod + exec.u64::mod end"; build_test!(source, &[a0, a1, b0, b1]).prop_expect_stack(&[c1, c0])?; } + #[test] fn shl_proptest(a in any::(), b in 0_u32..64) { let c = a.wrapping_shl(b); @@ -1272,7 +917,7 @@ proptest! { let source = " use.std::math::u64 begin - exec.u64::unchecked_shl + exec.u64::shl end"; build_test!(source, &[5, a0, a1, b as u64]).prop_expect_stack(&[c1, c0, 5])?; @@ -1289,7 +934,7 @@ proptest! { let source = " use.std::math::u64 begin - exec.u64::unchecked_shr + exec.u64::shr end"; build_test!(source, &[5, a0, a1, b as u64]).prop_expect_stack(&[c1, c0, 5])?; @@ -1306,7 +951,7 @@ proptest! { let source = " use.std::math::u64 begin - exec.u64::unchecked_rotl + exec.u64::rotl end"; build_test!(source, &[5, a0, a1, b as u64]).prop_expect_stack(&[c1, c0, 5])?; @@ -1323,7 +968,7 @@ proptest! { let source = " use.std::math::u64 begin - exec.u64::unchecked_rotr + exec.u64::rotr end"; build_test!(source, &[5, a0, a1, b as u64]).prop_expect_stack(&[c1, c0, 5])?; From 52a02ec308a6e8d34bb2ff7d5ef642cb0b44fc12 Mon Sep 17 00:00:00 2001 From: Andrey Khmuro Date: Thu, 23 Nov 2023 12:43:08 +0100 Subject: [PATCH 2/2] refactor: improve docs, update changelog --- CHANGELOG.md | 1 + docs/src/user_docs/stdlib/math/u64.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa593ff329..5846011a1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ #### Stdlib - Introduced `std::utils` module with `is_empty_word` procedure. Refactored `std::collections::smt` and `std::collections::smt64` to use the procedure (#1107). +- Removed `checked` versions of the instructions in the `std::math::u64` module (#1142). #### VM Internals - Introduced the `Event` decorator and an associated `on_event` handler on the `Host` trait (#1119). diff --git a/docs/src/user_docs/stdlib/math/u64.md b/docs/src/user_docs/stdlib/math/u64.md index a607e3e2df..5e3d06ec8a 100644 --- a/docs/src/user_docs/stdlib/math/u64.md +++ b/docs/src/user_docs/stdlib/math/u64.md @@ -10,7 +10,7 @@ All procedures assume that an unsigned 64-bit integer (u64) is encoded using two [a_hi, a_lo, ... ] ``` -It is important to be certain that procedures designated with `wrapping` and `overflowing` prefixes would not perform the check whether the input values are 32-bit limbs encoding valid u64 values. For example, `wrapping_add` and `overflowing_add` would not perform these checks, and therefore, if any of the top 4 stack elements is greater than $2^{32} - 1$, the operation will not fail but rather will produce an undefined result. +Many of the procedures listed below (e.g., `overflowing_add`, `wrapping_add`, `lt`) do not check whether the inputs are encoded using valid `u32` values. These procedures do not fail when the inputs are encoded incorrectly, but rather produce undefined results. Thus, it is important to be certain that limbs of input values are valid `u32` values prior to calling such procedures. ## Arithmetic operations