From 3cbba05ff0fd3434a851eb384bd8f92683f5f1db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Mon, 2 Oct 2023 10:34:00 -0300 Subject: [PATCH 01/12] Make Big UInt API functions naming consistent --- precompiles/Modexp.yul | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/precompiles/Modexp.yul b/precompiles/Modexp.yul index 7f72d23b..719279e7 100644 --- a/precompiles/Modexp.yul +++ b/precompiles/Modexp.yul @@ -36,7 +36,7 @@ object "ModExp" { /// @param start The pointer to the calldata where the big number starts. /// @param len The number of bytes that the big number occupies. /// @return res A boolean indicating whether the big number is zero (true) or not (false). - function bigNumberIsZero(start, len) -> res { + function bigUIntIsZero(start, len) -> res { // Initialize result as true, assuming the number is zero until proven otherwise. res := true @@ -73,16 +73,16 @@ object "ModExp" { /// @param start The pointer to the calldata where the big number starts. /// @param len The number of bytes that the big number occupies. /// @return res A boolean indicating whether the big number is one (true) or not (false). - function bigNumberIsOne(start, len) -> res { + function bigUIntIsOne(start, len) -> res { if len { let lastBytePtr := sub(add(start, len), 1) let lastByte := byte(0, calldataload(lastBytePtr)) // Check if the last byte is one. let lastByteIsOne := eq(lastByte, 1) - // Check if all other bytes are zero using the bigNumberIsZero function + // Check if all other bytes are zero using the bigUIntIsZero function // The length for this check is (len - 1) because we exclude the last byte. - let otherBytesAreZeroes := bigNumberIsZero(start, sub(len, 1)) + let otherBytesAreZeroes := bigUIntIsZero(start, sub(len, 1)) // The number is one if the last byte is one and all other bytes are zero. res := and(lastByteIsOne, otherBytesAreZeroes) @@ -442,7 +442,7 @@ object "ModExp" { // Note: This check covers the case where length of the modulo is zero. // base^exponent % 0 = 0 - if bigNumberIsZero(modPtr, modLen) { + if bigUIntIsZero(modPtr, modLen) { // Fulfill memory with all zeroes. for { let ptr } lt(ptr, modLen) { ptr := add(ptr, 32) } { mstore(ptr, 0) @@ -451,7 +451,7 @@ object "ModExp" { } // 1^exponent % modulus = 1 - if bigNumberIsOne(basePtr, baseLen) { + if bigUIntIsOne(basePtr, baseLen) { // Fulfill memory with all zeroes. for { let ptr } lt(ptr, modLen) { ptr := add(ptr, 32) } { mstore(ptr, 0) @@ -461,7 +461,7 @@ object "ModExp" { } // base^0 % modulus = 1 - if bigNumberIsZero(expPtr, expLength) { + if bigUIntIsZero(expPtr, expLength) { // Fulfill memory with all zeroes. for { let ptr } lt(ptr, modLen) { ptr := add(ptr, 32) } { mstore(ptr, 0) @@ -471,7 +471,7 @@ object "ModExp" { } // 0^exponent % modulus = 0 - if bigNumberIsZero(basePtr, baseLen) { + if bigUIntIsZero(basePtr, baseLen) { // Fulfill memory with all zeroes. for { let ptr } lt(ptr, modLen) { ptr := add(ptr, 32) } { mstore(ptr, 0) From e4882fc799e0bbaa7fb0eafdaad689bce071c68b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Mon, 2 Oct 2023 10:36:17 -0300 Subject: [PATCH 02/12] Refactor `bigUIntAdd` variable names --- precompiles/Modexp.yul | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/precompiles/Modexp.yul b/precompiles/Modexp.yul index 719279e7..16d373ca 100644 --- a/precompiles/Modexp.yul +++ b/precompiles/Modexp.yul @@ -309,35 +309,35 @@ object "ModExp" { } /// @notice Add two big numbers. - /// @param lhsPtr The pointer where the big number on the left operand starts. - /// @param rhsPtr The pointer where the big number on right operand starts. + /// @param augendPtr The pointer where the big number on the left operand starts. + /// @param addendPtr The pointer where the big number on right operand starts. /// @param nLimbs The number of 32-byte words that the big numbers occupy. /// @param resPtr The pointer where the result of the addition will be stored. - /// @return isOverflow A boolean indicating whether the addition overflowed (true) or not (false). - function bigUIntAdd(lhsPtr, rhsPtr, nLimbs, resPtr) -> isOverflow { + /// @return overflowed A boolean indicating whether the addition overflowed (true) or not (false). + function bigUIntAdd(augendPtr, addendPtr, nLimbs, resPtr) -> overflowed { let totalLength := mul(nLimbs, LIMB_SIZE_IN_BYTES()) let carry := 0 - let lhsCurrentLimbPtr := add(lhsPtr, totalLength) - let rhsCurrentLimbPtr := add(rhsPtr, totalLength) + let augendCurrentLimbPtr := add(augendPtr, totalLength) + let addendCurrentLimbPtr := add(addendPtr, totalLength) // Loop through each full 32-byte word to add the two big numbers. for {let i := 1 } or(eq(i,nLimbs), lt(i, nLimbs)) { i := add(i, 1) } { // Check limb from the right (least significant limb) let actualLimbOffset := mul(LIMB_SIZE_IN_BYTES(), i) - lhsCurrentLimbPtr := sub(lhsCurrentLimbPtr, actualLimbOffset) - rhsCurrentLimbPtr := sub(rhsCurrentLimbPtr, actualLimbOffset) + augendCurrentLimbPtr := sub(augendCurrentLimbPtr, actualLimbOffset) + addendCurrentLimbPtr := sub(addendCurrentLimbPtr, actualLimbOffset) - let rhsLimb := mload(rhsCurrentLimbPtr) - let lhsLimb := mload(lhsCurrentLimbPtr) - let sumResult, overflow := overflowingAdd(lhsLimb, rhsLimb) - let sumWithPreviousCarry, carrySumOverflow := overflowingAdd(sumResult, carry) - sumResult := sumWithPreviousCarry + let addendLimb := mload(addendCurrentLimbPtr) + let augendLimb := mload(augendCurrentLimbPtr) + let sum, overflow := overflowingAdd(augendLimb, addendLimb) + let sumWithPreviousCarry, carrySumOverflow := overflowingAdd(sum, carry) + sum := sumWithPreviousCarry carry := or(overflow, carrySumOverflow) let limbResultPtr := sub(add(resPtr,totalLength),actualLimbOffset) - mstore(limbResultPtr, sumResult) + mstore(limbResultPtr, sum) } - isOverflow := carry + overflowed := carry } From 3e0f219286d7991b7f3ca187e6f4f00de5191c74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Mon, 2 Oct 2023 10:41:26 -0300 Subject: [PATCH 03/12] Refactor `bigUIntMul` variable names --- precompiles/Modexp.yul | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/precompiles/Modexp.yul b/precompiles/Modexp.yul index 16d373ca..37399ffb 100644 --- a/precompiles/Modexp.yul +++ b/precompiles/Modexp.yul @@ -389,11 +389,11 @@ object "ModExp" { } } /// @notice Performs the multiplication between two bigUInts - /// @dev The result is stored from `mulResultPtr` to `mulResultPtr + (LIMB_SIZE * nLimbs)`. - /// @param lhsPtr The start index in memory of the first number. - /// @param rhsPtr The start index in memory of the second number. + /// @dev The result is stored from `productPtr` to `productPtr + (LIMB_SIZE * nLimbs)`. + /// @param multiplicandPtr The start index in memory of the first number. + /// @param multiplierPtr The start index in memory of the second number. /// @param nLimbs The number of limbs needed to represent the operands. - function bigUIntMul(lhsPtr, rhsPtr, nLimbs, mulResultPtr) { + function bigUIntMul(multiplicandPtr, multiplierPtr, nLimbs, productPtr) { let retIndex, retWordAfter, retWordBefore // Iterating over each limb in the first number. for { let i := nLimbs } gt(i, 0) { i := sub(i, 1) } { @@ -402,14 +402,14 @@ object "ModExp" { // Iterating over each limb in the second number. for { let j := nLimbs } gt(j, 0) { j := sub(j, 1) } { // Loading the i-th and j-th limbs of the first and second numbers. - let word1 := mload(add(lhsPtr, mul(LIMB_SIZE_IN_BYTES(), sub(i, 1)))) - let word2 := mload(add(rhsPtr, mul(LIMB_SIZE_IN_BYTES(), sub(j, 1)))) + let word1 := mload(add(multiplicandPtr, mul(LIMB_SIZE_IN_BYTES(), sub(i, 1)))) + let word2 := mload(add(multiplierPtr, mul(LIMB_SIZE_IN_BYTES(), sub(j, 1)))) let product, carryFlag := overflowingAdd(mul(word1, word2), carry) carry := add(getHighestHalfOfMultiplication(word1, word2), carryFlag) // Calculate the index to store the product. - retIndex := add(mulResultPtr, mul(sub(add(i, j), 1), LIMB_SIZE_IN_BYTES())) + retIndex := add(productPtr, mul(sub(add(i, j), 1), LIMB_SIZE_IN_BYTES())) retWordBefore := mload(retIndex) // Load the previous value at the result index. retWordAfter, carryFlag := overflowingAdd(retWordBefore, product) @@ -418,7 +418,7 @@ object "ModExp" { } // Store the last word which comes from the final carry. - retIndex := add(mulResultPtr, mul(sub(i, 1), LIMB_SIZE_IN_BYTES())) + retIndex := add(productPtr, mul(sub(i, 1), LIMB_SIZE_IN_BYTES())) mstore(retIndex, carry) } } From 34265a3e01cd52b49e00d79d2680f8c12273f02d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Mon, 2 Oct 2023 10:58:16 -0300 Subject: [PATCH 04/12] Refactor `subLimbsWithBorrow` --- precompiles/Modexp.yul | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/precompiles/Modexp.yul b/precompiles/Modexp.yul index 37399ffb..da09914f 100644 --- a/precompiles/Modexp.yul +++ b/precompiles/Modexp.yul @@ -353,16 +353,13 @@ object "ModExp" { /// account of the borrow bit /// in lshPointer and rhsPointer. /// @dev Reference: https://github.com/lambdaclass/lambdaworks/blob/main/math/src/unsigned_integer/element.rs#L785 - /// @param leftLimb The left side of the difference (i.e. the a in a - b). - /// @param rightLimb The right side of the difference (i.e. the b in a - b). - /// @return subtractionResult i.e. the c in c = a - b. - /// @return returnBorrow If there was any borrow on the subtraction, is returned as 1. - function subLimbsWithBorrow(leftLimb, rightLimb, limbBorrow) -> subtractionResult, returnBorrow { - let rightPlusBorrow := add(rightLimb, limbBorrow) - subtractionResult := sub(leftLimb, rightPlusBorrow) - if gt(subtractionResult, leftLimb) { - returnBorrow := 1 - } + /// @param minuend The left side of the difference (i.e. the a in a - b). + /// @param subtrahend The right side of the difference (i.e. the b in a - b). + /// @return difference i.e. the c in c = a - b. + /// @return overflowed If there was any borrow on the subtraction, is returned as 1. + function overflowingSubWithBorrow(minuend, subtrahend, borrow) -> difference, overflowed { + difference := sub(minuend, add(subtrahend, borrow)) + overflowed := gt(difference, minuend) } /// @notice Computes the BigUint subtraction between the number stored /// in lshPointer and rhsPointer. From b623ddb4efb9ca51fcb483342c583d44259cc691 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Mon, 2 Oct 2023 11:02:57 -0300 Subject: [PATCH 05/12] Refactor `bigUintSubtractionWithBorrow` --- precompiles/Modexp.yul | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/precompiles/Modexp.yul b/precompiles/Modexp.yul index da09914f..710c975b 100644 --- a/precompiles/Modexp.yul +++ b/precompiles/Modexp.yul @@ -362,27 +362,20 @@ object "ModExp" { overflowed := gt(difference, minuend) } /// @notice Computes the BigUint subtraction between the number stored - /// in lshPointer and rhsPointer. + /// in minuendPtr and subtrahendPtr. /// @dev Reference: https://github.com/lambdaclass/lambdaworks/blob/main/math/src/unsigned_integer/element.rs#L795 - /// @param lhsPointer The start of the left hand side subtraction Big Number. - /// @param rhsPointer The start of the right hand side subtraction Big Number. - /// @return numberOfLimbs The number of limbs of both numbers. - /// @return resultPointer Where the result will be stored. - function bigUintSubtractionWithBorrow(lhsPointer, rhsPointer, numberOfLimbs, resultPointer) -> resultPointer, borrow { - let leftIthLimbValue - let rightIthLimbValue - let ithLimbBorrowResult - let ithLimbSubtractionResult - let borrow := 0 + /// @param minuendPtr The start of the left hand side subtraction Big Number. + /// @param subtrahendPtr The start of the right hand side subtraction Big Number. + /// @return nLimbs The number of limbs of both numbers. + /// @return differencePtr Where the result will be stored. + function bigUIntSubWithBorrow(minuendPtr, subtrahendPtr, nLimbs, differencePtr) -> borrow { let limbOffset := 0 - for {let i := numberOfLimbs} gt(i, 0) {i := sub(i, 1)} { + for {let i := nLimbs} gt(i, 0) {i := sub(i, 1)} { limbOffset := mul(sub(i,1), 32) - leftIthLimbValue := getLimbValueAtOffset(lhsPointer, limbOffset) - rightIthLimbValue := getLimbValueAtOffset(rhsPointer, limbOffset) - ithLimbSubtractionResult, borrow := - subLimbsWithBorrow(leftIthLimbValue, rightIthLimbValue, borrow) - storeLimbValueAtOffset(resultPointer, limbOffset, ithLimbSubtractionResult) - + let minuendCurrentLimb := getLimbValueAtOffset(minuendPtr, limbOffset) + let subtrahendCurrentLimb := getLimbValueAtOffset(subtrahendPtr, limbOffset) + let differenceCurrentLimb, borrow := overflowingSubWithBorrow(minuendCurrentLimb, subtrahendCurrentLimb, borrow) + storeLimbValueAtOffset(differencePtr, limbOffset, differenceCurrentLimb) } } /// @notice Performs the multiplication between two bigUInts From 628c67dc090261ef09b932d677d5bc873f4b1747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Mon, 2 Oct 2023 11:09:20 -0300 Subject: [PATCH 06/12] Refactor `bigUIntAdd` --- precompiles/Modexp.yul | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/precompiles/Modexp.yul b/precompiles/Modexp.yul index 710c975b..18208831 100644 --- a/precompiles/Modexp.yul +++ b/precompiles/Modexp.yul @@ -312,9 +312,9 @@ object "ModExp" { /// @param augendPtr The pointer where the big number on the left operand starts. /// @param addendPtr The pointer where the big number on right operand starts. /// @param nLimbs The number of 32-byte words that the big numbers occupy. - /// @param resPtr The pointer where the result of the addition will be stored. + /// @param sumPtr The pointer where the result of the addition will be stored. /// @return overflowed A boolean indicating whether the addition overflowed (true) or not (false). - function bigUIntAdd(augendPtr, addendPtr, nLimbs, resPtr) -> overflowed { + function bigUIntAdd(augendPtr, addendPtr, nLimbs, sumPtr) -> overflowed { let totalLength := mul(nLimbs, LIMB_SIZE_IN_BYTES()) let carry := 0 @@ -324,9 +324,9 @@ object "ModExp" { // Loop through each full 32-byte word to add the two big numbers. for {let i := 1 } or(eq(i,nLimbs), lt(i, nLimbs)) { i := add(i, 1) } { // Check limb from the right (least significant limb) - let actualLimbOffset := mul(LIMB_SIZE_IN_BYTES(), i) - augendCurrentLimbPtr := sub(augendCurrentLimbPtr, actualLimbOffset) - addendCurrentLimbPtr := sub(addendCurrentLimbPtr, actualLimbOffset) + let currentLimbOffset := mul(LIMB_SIZE_IN_BYTES(), i) + augendCurrentLimbPtr := sub(augendCurrentLimbPtr, currentLimbOffset) + addendCurrentLimbPtr := sub(addendCurrentLimbPtr, currentLimbOffset) let addendLimb := mload(addendCurrentLimbPtr) let augendLimb := mload(augendCurrentLimbPtr) @@ -334,7 +334,7 @@ object "ModExp" { let sumWithPreviousCarry, carrySumOverflow := overflowingAdd(sum, carry) sum := sumWithPreviousCarry carry := or(overflow, carrySumOverflow) - let limbResultPtr := sub(add(resPtr,totalLength),actualLimbOffset) + let limbResultPtr := sub(add(sumPtr,totalLength), currentLimbOffset) mstore(limbResultPtr, sum) } overflowed := carry From aed2a322bb6822b5650d27c2778f3f2f40c4547d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Mon, 2 Oct 2023 11:23:13 -0300 Subject: [PATCH 07/12] Fix `bigUIntSubWithBorrow` --- precompiles/Modexp.yul | 3 +++ 1 file changed, 3 insertions(+) diff --git a/precompiles/Modexp.yul b/precompiles/Modexp.yul index 18208831..d38caed3 100644 --- a/precompiles/Modexp.yul +++ b/precompiles/Modexp.yul @@ -369,6 +369,9 @@ object "ModExp" { /// @return nLimbs The number of limbs of both numbers. /// @return differencePtr Where the result will be stored. function bigUIntSubWithBorrow(minuendPtr, subtrahendPtr, nLimbs, differencePtr) -> borrow { + let minuendCurrentLimb + let subtrahendCurrentLimb + let differenceCurrentLimb let limbOffset := 0 for {let i := nLimbs} gt(i, 0) {i := sub(i, 1)} { limbOffset := mul(sub(i,1), 32) From 74ae040456ca57cfbcff3b96536d90f257b380cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Mon, 2 Oct 2023 11:24:03 -0300 Subject: [PATCH 08/12] Format `storeLimbValueAtOffset` --- precompiles/Modexp.yul | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/precompiles/Modexp.yul b/precompiles/Modexp.yul index d38caed3..cdd8a1e5 100644 --- a/precompiles/Modexp.yul +++ b/precompiles/Modexp.yul @@ -346,7 +346,7 @@ object "ModExp" { } function storeLimbValueAtOffset(limbPointer, anOffset, aValue) { - mstore(add(limbPointer, anOffset), aValue) + mstore(add(limbPointer, anOffset), aValue) } /// @notice Computes the difference between two 256 bit number and keeps From 2d954b29f19c65eefcfab80f5c5aeb8d4360065b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Mon, 2 Oct 2023 11:32:02 -0300 Subject: [PATCH 09/12] Refactor `bigUIntBitOr` Made it consistent with the rest of the code convention and naming --- precompiles/Modexp.yul | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/precompiles/Modexp.yul b/precompiles/Modexp.yul index cdd8a1e5..dcd25a4b 100644 --- a/precompiles/Modexp.yul +++ b/precompiles/Modexp.yul @@ -119,7 +119,7 @@ object "ModExp" { /// @param resPtr The pointer to where you want the result to be stored function bigUIntBitOr(lhsPtr, rhsPtr, nLimbs, resPtr) { // +------------+-----------------------+-------------------------------+-------------------------------+-------------------------------+-----------------+-----------------+--------------------------------------+ - // | Iteration | offset_i | ptr_lhs_i | ptr_rhs_i | ptr_res_i | value_lhs_i | value_rhs_i | value_res_i | + // | Iteration | currentOffset | lhsCurrentPtr | rhsCurrentPtr | resCurrentPtr | lhsCurrentValue | rhsCurrentValue | resCurrentValue | // +------------+-----------------------+-------------------------------+-------------------------------+-------------------------------+-----------------+-----------------+--------------------------------------+ // | 0 | +0x00 | lhsPtr + 0x00 | rhsPtr + 0x00 | resPtr + 0x00 | lhs[0] | rhs[0] | or(lhs[0], rhs[0]) | // | 1 | +0x20 | lhsPtr + 0x20 | rhsPtr + 0x20 | resPtr + 0x20 | lhs[1] | rhs[1] | or(lhs[1], rhs[1]) | @@ -131,15 +131,14 @@ object "ModExp" { // +------------+-----------------------+-------------------------------+-------------------------------+-------------------------------+-----------------+-----------------+--------------------------------------+ let finalOffset := shl(5, nLimbs) // == ( LIMB_SIZE * nLimbs ) == (32 * nLimbs) - for { let offset_i := 0 } lt(offset_i, finalOffset) { offset_i := add(offset_i, 0x20) } - { - let ptr_lhs_i := add(lhsPtr, offset_i) - let ptr_rhs_i := add(rhsPtr, offset_i) - let ptr_res_i := add(resPtr, offset_i) - let value_lhs_i := mload(ptr_lhs_i) - let value_rhs_i := mload(ptr_rhs_i) - let value_res_i := or(value_lhs_i, value_rhs_i) - mstore(ptr_res_i, value_res_i) + for { let currentOffset := 0 } lt(currentOffset, finalOffset) { currentOffset := add(currentOffset, 0x20) } { + let lhsCurrentPtr := add(lhsPtr, currentOffset) + let rhsCurrentPtr := add(rhsPtr, currentOffset) + let resCurrentPtr := add(resPtr, currentOffset) + let lhsCurrentValue := mload(lhsCurrentPtr) + let rhsCurrentValue := mload(rhsCurrentPtr) + let resCurrentValue := or(lhsCurrentValue, rhsCurrentValue) + mstore(resCurrentPtr, resCurrentValue) } } @@ -322,7 +321,7 @@ object "ModExp" { let addendCurrentLimbPtr := add(addendPtr, totalLength) // Loop through each full 32-byte word to add the two big numbers. - for {let i := 1 } or(eq(i,nLimbs), lt(i, nLimbs)) { i := add(i, 1) } { + for { let i := 1 } or(eq(i,nLimbs), lt(i, nLimbs)) { i := add(i, 1) } { // Check limb from the right (least significant limb) let currentLimbOffset := mul(LIMB_SIZE_IN_BYTES(), i) augendCurrentLimbPtr := sub(augendCurrentLimbPtr, currentLimbOffset) @@ -361,6 +360,7 @@ object "ModExp" { difference := sub(minuend, add(subtrahend, borrow)) overflowed := gt(difference, minuend) } + /// @notice Computes the BigUint subtraction between the number stored /// in minuendPtr and subtrahendPtr. /// @dev Reference: https://github.com/lambdaclass/lambdaworks/blob/main/math/src/unsigned_integer/element.rs#L795 @@ -373,7 +373,7 @@ object "ModExp" { let subtrahendCurrentLimb let differenceCurrentLimb let limbOffset := 0 - for {let i := nLimbs} gt(i, 0) {i := sub(i, 1)} { + for { let i := nLimbs } gt(i, 0) { i := sub(i, 1) } { limbOffset := mul(sub(i,1), 32) let minuendCurrentLimb := getLimbValueAtOffset(minuendPtr, limbOffset) let subtrahendCurrentLimb := getLimbValueAtOffset(subtrahendPtr, limbOffset) @@ -381,6 +381,7 @@ object "ModExp" { storeLimbValueAtOffset(differencePtr, limbOffset, differenceCurrentLimb) } } + /// @notice Performs the multiplication between two bigUInts /// @dev The result is stored from `productPtr` to `productPtr + (LIMB_SIZE * nLimbs)`. /// @param multiplicandPtr The start index in memory of the first number. From 0cc5e9b60cb911b35045322606e3d1bebfc6c294 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Mon, 2 Oct 2023 11:37:57 -0300 Subject: [PATCH 10/12] Refactor `bigUIntCondSelect` Made it consistent with the rest of the code convention and naming --- precompiles/Modexp.yul | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/precompiles/Modexp.yul b/precompiles/Modexp.yul index dcd25a4b..251c4753 100644 --- a/precompiles/Modexp.yul +++ b/precompiles/Modexp.yul @@ -99,15 +99,14 @@ object "ModExp" { /// @param mask Either `0x0` or `0xFF...FF`. function bigUIntCondSelect(lhsPtr, rhsPtr, resPtr, nLimbs, mask) { let finalOffset := shl(5, nLimbs) // == ( LIMB_SIZE * nLimbs ) == (32 * nLimbs) - for { let offset_i := 0 } lt(offset_i, finalOffset) { offset_i := add(offset_i, 0x20) } - { - let ptr_lhs_i := add(lhsPtr, offset_i) - let ptr_rhs_i := add(rhsPtr, offset_i) - let ptr_res_i := add(resPtr, offset_i) - let value_lhs_i := mload(ptr_lhs_i) - let value_rhs_i := mload(ptr_rhs_i) - let value_res_i := xor(value_lhs_i, and(mask, xor(value_lhs_i, value_rhs_i))) // a ^ (ct & (a ^ b)) - mstore(ptr_res_i, value_res_i) + for { let currentOffset := 0 } lt(currentOffset, finalOffset) { currentOffset := add(currentOffset, 0x20) } { + let lhsCurrentPtr := add(lhsPtr, currentOffset) + let rhsCurrentPtr := add(rhsPtr, currentOffset) + let resCurrentPtr := add(resPtr, currentOffset) + let lhsCurrentValue := mload(lhsCurrentPtr) + let rhsCurrentValue := mload(rhsCurrentPtr) + let resCurrentValue := xor(lhsCurrentValue, and(mask, xor(lhsCurrentValue, rhsCurrentValue))) // a ^ (ct & (a ^ b)) + mstore(resCurrentPtr, resCurrentValue) } } From 10ba59d79537cca50bf55aad0ecef57d2a87c88b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Mon, 2 Oct 2023 11:43:35 -0300 Subject: [PATCH 11/12] Reorder `overflowingSubWithBorrow` --- precompiles/Modexp.yul | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/precompiles/Modexp.yul b/precompiles/Modexp.yul index 251c4753..d4598221 100644 --- a/precompiles/Modexp.yul +++ b/precompiles/Modexp.yul @@ -24,6 +24,17 @@ object "ModExp" { overflowed := lt(sum, augend) } + /// @notice Computes the difference between two 256 bit number and keeps + /// account of the borrow bit. + /// @param minuend The left side of the difference (i.e. the a in a - b). + /// @param subtrahend The right side of the difference (i.e. the b in a - b). + /// @return difference i.e. the c in c = a - b. + /// @return overflowed If there was any borrow on the subtraction, is returned as 1. + function overflowingSubWithBorrow(minuend, subtrahend, borrow) -> difference, overflowed { + difference := sub(minuend, add(subtrahend, borrow)) + overflowed := gt(difference, minuend) + } + /// @notice Retrieves the highest half of the multiplication result. /// @param multiplicand The value to multiply. /// @param multiplier The multiplier. @@ -347,19 +358,6 @@ object "ModExp" { mstore(add(limbPointer, anOffset), aValue) } - /// @notice Computes the difference between two 256 bit number and keeps - /// account of the borrow bit - /// in lshPointer and rhsPointer. - /// @dev Reference: https://github.com/lambdaclass/lambdaworks/blob/main/math/src/unsigned_integer/element.rs#L785 - /// @param minuend The left side of the difference (i.e. the a in a - b). - /// @param subtrahend The right side of the difference (i.e. the b in a - b). - /// @return difference i.e. the c in c = a - b. - /// @return overflowed If there was any borrow on the subtraction, is returned as 1. - function overflowingSubWithBorrow(minuend, subtrahend, borrow) -> difference, overflowed { - difference := sub(minuend, add(subtrahend, borrow)) - overflowed := gt(difference, minuend) - } - /// @notice Computes the BigUint subtraction between the number stored /// in minuendPtr and subtrahendPtr. /// @dev Reference: https://github.com/lambdaclass/lambdaworks/blob/main/math/src/unsigned_integer/element.rs#L795 From fa0c59fdbf1f845fab2c49621582f2528b0924a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Mon, 2 Oct 2023 12:41:28 -0300 Subject: [PATCH 12/12] Move comment to modexp API Docs section --- docs/src/SUMMARY.md | 1 + docs/src/modexp/api.md | 27 +++++++++++++++++++++++++++ precompiles/Modexp.yul | 12 ------------ 3 files changed, 28 insertions(+), 12 deletions(-) create mode 100644 docs/src/modexp/api.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 6df7d600..05aa6dbf 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -13,4 +13,5 @@ - [Optimizations](ecpairing/optimizations.md) - [ModExp]() - [Specification](modexp/spec.md) + - [API Docs](modexp/api.md) - [Optimizations](modexp/optimizations.md) diff --git a/docs/src/modexp/api.md b/docs/src/modexp/api.md new file mode 100644 index 00000000..432d05ec --- /dev/null +++ b/docs/src/modexp/api.md @@ -0,0 +1,27 @@ +# API Docs + +## Big Unsigned Integers Arithmetic + +### `bigUIntAdd` + +### `bigUIntSubWithBorrow` + +### `bigUIntMul` + +### `bigUIntBitOr` + +``` ++------------+-----------------------+-------------------------------+-------------------------------+-------------------------------+-----------------+-----------------+--------------------------------------+ +| Iteration | currentOffset | lhsCurrentPtr | rhsCurrentPtr | resCurrentPtr | lhsCurrentValue | rhsCurrentValue | resCurrentValue | ++------------+-----------------------+-------------------------------+-------------------------------+-------------------------------+-----------------+-----------------+--------------------------------------+ +| 0 | +0x00 | lhsPtr + 0x00 | rhsPtr + 0x00 | resPtr + 0x00 | lhs[0] | rhs[0] | or(lhs[0], rhs[0]) | +| 1 | +0x20 | lhsPtr + 0x20 | rhsPtr + 0x20 | resPtr + 0x20 | lhs[1] | rhs[1] | or(lhs[1], rhs[1]) | +| 2 | +0x40 | lhsPtr + 0x40 | rhsPtr + 0x40 | resPtr + 0x40 | lhs[2] | rhs[2] | or(lhs[2], rhs[2]) | +| | | | | | | | | +| ... | ... | ... | ... | ... | ... | ... | ... | +| | | | | | | | | +| nLimbs - 1 | +(0x20 * (nLimbs - 1) | lhsPtr + (0x20 * (nLimbs - 1) | rhsPtr + (0x20 * (nLimbs - 1) | resPtr + (0x20 * (nLimbs - 1) | lhs[nLimbs - 1] | rhs[nLimbs - 1] | or(lhs[nLimbs - 1], rhs[nLimbs - 1]) | ++------------+-----------------------+-------------------------------+-------------------------------+-------------------------------+-----------------+-----------------+--------------------------------------+ +``` + +### `bigUIntCondSelect` \ No newline at end of file diff --git a/precompiles/Modexp.yul b/precompiles/Modexp.yul index d4598221..b851071f 100644 --- a/precompiles/Modexp.yul +++ b/precompiles/Modexp.yul @@ -128,18 +128,6 @@ object "ModExp" { /// @param nLimbs The number of limbs needed to represent the operands. /// @param resPtr The pointer to where you want the result to be stored function bigUIntBitOr(lhsPtr, rhsPtr, nLimbs, resPtr) { - // +------------+-----------------------+-------------------------------+-------------------------------+-------------------------------+-----------------+-----------------+--------------------------------------+ - // | Iteration | currentOffset | lhsCurrentPtr | rhsCurrentPtr | resCurrentPtr | lhsCurrentValue | rhsCurrentValue | resCurrentValue | - // +------------+-----------------------+-------------------------------+-------------------------------+-------------------------------+-----------------+-----------------+--------------------------------------+ - // | 0 | +0x00 | lhsPtr + 0x00 | rhsPtr + 0x00 | resPtr + 0x00 | lhs[0] | rhs[0] | or(lhs[0], rhs[0]) | - // | 1 | +0x20 | lhsPtr + 0x20 | rhsPtr + 0x20 | resPtr + 0x20 | lhs[1] | rhs[1] | or(lhs[1], rhs[1]) | - // | 2 | +0x40 | lhsPtr + 0x40 | rhsPtr + 0x40 | resPtr + 0x40 | lhs[2] | rhs[2] | or(lhs[2], rhs[2]) | - // | | | | | | | | | - // | ... | ... | ... | ... | ... | ... | ... | ... | - // | | | | | | | | | - // | nLimbs - 1 | +(0x20 * (nLimbs - 1) | lhsPtr + (0x20 * (nLimbs - 1) | rhsPtr + (0x20 * (nLimbs - 1) | resPtr + (0x20 * (nLimbs - 1) | lhs[nLimbs - 1] | rhs[nLimbs - 1] | or(lhs[nLimbs - 1], rhs[nLimbs - 1]) | - // +------------+-----------------------+-------------------------------+-------------------------------+-------------------------------+-----------------+-----------------+--------------------------------------+ - let finalOffset := shl(5, nLimbs) // == ( LIMB_SIZE * nLimbs ) == (32 * nLimbs) for { let currentOffset := 0 } lt(currentOffset, finalOffset) { currentOffset := add(currentOffset, 0x20) } { let lhsCurrentPtr := add(lhsPtr, currentOffset)