From aaad4dfd0f3aff1c39443a1e62958bf6eb9860aa Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Sat, 19 Oct 2019 21:50:53 +0300 Subject: [PATCH 1/2] Optimize rpow(x,n,base) for the case x != 0 && n == 0 (291 gas vs 383 gas) --- src/jug.sol | 41 ++++++++++++++++++++++------------------- src/pot.sol | 33 ++++++++++++++++++--------------- 2 files changed, 40 insertions(+), 34 deletions(-) diff --git a/src/jug.sol b/src/jug.sol index 1188c9cf..3d4e7207 100644 --- a/src/jug.sol +++ b/src/jug.sol @@ -38,27 +38,30 @@ contract Jug is DSNote { // --- Math --- function rpow(uint x, uint n, uint b) internal pure returns (uint z) { - assembly { - switch x case 0 {switch n case 0 {z := b} default {z := 0}} - default { - switch mod(n, 2) case 0 { z := b } default { z := x } - let half := div(b, 2) // for rounding. - for { n := div(n, 2) } n { n := div(n,2) } { - let xx := mul(x, x) - if iszero(eq(div(xx, x), x)) { revert(0,0) } - let xxRound := add(xx, half) - if lt(xxRound, xx) { revert(0,0) } - x := div(xxRound, b) - if mod(n,2) { - let zx := mul(z, x) - if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0,0) } - let zxRound := add(zx, half) - if lt(zxRound, zx) { revert(0,0) } - z := div(zxRound, b) + assembly { + switch n case 0 { z := b } + default { + switch x case 0 { z := 0 } + default { + switch mod(n, 2) case 0 { z := b } default { z := x } + let half := div(b, 2) // for rounding. + for { n := div(n, 2) } n { n := div(n,2) } { + let xx := mul(x, x) + if iszero(eq(div(xx, x), x)) { revert(0,0) } + let xxRound := add(xx, half) + if lt(xxRound, xx) { revert(0,0) } + x := div(xxRound, b) + if mod(n,2) { + let zx := mul(z, x) + if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0,0) } + let zxRound := add(zx, half) + if lt(zxRound, zx) { revert(0,0) } + z := div(zxRound, b) + } + } + } } - } } - } } uint256 constant ONE = 10 ** 27; function add(uint x, uint y) internal pure returns (uint z) { diff --git a/src/pot.sol b/src/pot.sol index 0b18bc8f..3df066ea 100644 --- a/src/pot.sol +++ b/src/pot.sol @@ -77,22 +77,25 @@ contract Pot is DSNote { uint256 constant ONE = 10 ** 27; function rpow(uint x, uint n, uint base) internal pure returns (uint z) { assembly { - switch x case 0 {switch n case 0 {z := base} default {z := 0}} + switch n case 0 { z := base } default { - switch mod(n, 2) case 0 { z := base } default { z := x } - let half := div(base, 2) // for rounding. - for { n := div(n, 2) } n { n := div(n,2) } { - let xx := mul(x, x) - if iszero(eq(div(xx, x), x)) { revert(0,0) } - let xxRound := add(xx, half) - if lt(xxRound, xx) { revert(0,0) } - x := div(xxRound, base) - if mod(n,2) { - let zx := mul(z, x) - if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0,0) } - let zxRound := add(zx, half) - if lt(zxRound, zx) { revert(0,0) } - z := div(zxRound, base) + switch x case 0 { z := 0 } + default { + switch mod(n, 2) case 0 { z := base } default { z := x } + let half := div(base, 2) // for rounding. + for { n := div(n, 2) } n { n := div(n,2) } { + let xx := mul(x, x) + if iszero(eq(div(xx, x), x)) { revert(0,0) } + let xxRound := add(xx, half) + if lt(xxRound, xx) { revert(0,0) } + x := div(xxRound, base) + if mod(n,2) { + let zx := mul(z, x) + if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0,0) } + let zxRound := add(zx, half) + if lt(zxRound, zx) { revert(0,0) } + z := div(zxRound, base) + } } } } From f71cd486f9c1b0d40cdaff217cfc39509b7cc28e Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Sat, 19 Oct 2019 22:11:00 +0300 Subject: [PATCH 2/2] Simplify overflow check for squaring in rpow(x,n,base) --- src/jug.sol | 2 +- src/pot.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jug.sol b/src/jug.sol index 3d4e7207..fc45e07a 100644 --- a/src/jug.sol +++ b/src/jug.sol @@ -47,7 +47,7 @@ contract Jug is DSNote { let half := div(b, 2) // for rounding. for { n := div(n, 2) } n { n := div(n,2) } { let xx := mul(x, x) - if iszero(eq(div(xx, x), x)) { revert(0,0) } + if shr(128, x) { revert(0,0) } let xxRound := add(xx, half) if lt(xxRound, xx) { revert(0,0) } x := div(xxRound, b) diff --git a/src/pot.sol b/src/pot.sol index 3df066ea..4b070f1a 100644 --- a/src/pot.sol +++ b/src/pot.sol @@ -85,7 +85,7 @@ contract Pot is DSNote { let half := div(base, 2) // for rounding. for { n := div(n, 2) } n { n := div(n,2) } { let xx := mul(x, x) - if iszero(eq(div(xx, x), x)) { revert(0,0) } + if shr(128, x) { revert(0,0) } let xxRound := add(xx, half) if lt(xxRound, xx) { revert(0,0) } x := div(xxRound, base)