From fa0f82f23a3e3e34d6c4d3246a0477574fc78d7c Mon Sep 17 00:00:00 2001 From: Vaishnavi Singh Date: Thu, 12 Sep 2024 01:15:55 +0530 Subject: [PATCH 1/7] boundLog added --- testdata/default/cheats/Wallet.t.sol | 204 ++++++++++++++++++++++++++- 1 file changed, 198 insertions(+), 6 deletions(-) diff --git a/testdata/default/cheats/Wallet.t.sol b/testdata/default/cheats/Wallet.t.sol index 5a7035876cd0..96c5fac93e35 100644 --- a/testdata/default/cheats/Wallet.t.sol +++ b/testdata/default/cheats/Wallet.t.sol @@ -9,10 +9,20 @@ contract Foo {} contract WalletTest is DSTest { Vm constant vm = Vm(HEVM_ADDRESS); - uint256 internal constant Q = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141; + uint256 internal constant Q = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141; // constant acc to secp256k1 for generating PK uint256 private constant UINT256_MAX = - 115792089237316195423570985008687907853269984665640564039457584007913129639935; + 115792089237316195423570985008687907853269984665640564039457584007913129639935; // max num stored in uin256 + + enum DistributionType { Uniform, Logarithmic } + struct ParamConfig { + uint256 min; + uint256 max; + DistributionType distributionType; + uint256[] fixtures; + uint256[] excluded; + } + // converts Public key to Ethereum address using keccak256 hash function addressOf(uint256 x, uint256 y) internal pure returns (address) { return address(uint160(uint256(keccak256(abi.encode(x, y))))); } @@ -44,6 +54,15 @@ contract WalletTest is DSTest { } } + + + + + + + + + // tests that wallet is created with the address derived from PK and label is set correctly function testCreateWalletStringPrivAndLabel() public { bytes memory privKey = "this is a priv key"; Vm.Wallet memory wallet = vm.createWallet(string(privKey)); @@ -60,6 +79,7 @@ contract WalletTest is DSTest { assertEq(label, string(privKey), "labelled address != wallet.addr"); } + // tests creation of PK using a seed function testCreateWalletPrivKeyNoLabel(uint256 pkSeed) public { uint256 pk = bound(pkSeed, 1, Q - 1); @@ -74,6 +94,7 @@ contract WalletTest is DSTest { assertEq(expectedAddr, wallet.addr); } + // tests creation of PK using a seed and checks labels too function testCreateWalletPrivKeyWithLabel(uint256 pkSeed) public { string memory label = "labelled wallet"; @@ -92,7 +113,7 @@ contract WalletTest is DSTest { string memory expectedLabel = vm.getLabel(wallet.addr); assertEq(expectedLabel, label, "labelled address != wallet.addr"); } - + // tests signing a has using PK and checks the address recovered from the signautre is correct wallet address function testSignWithWalletDigest(uint256 pkSeed, bytes32 digest) public { uint256 pk = bound(pkSeed, 1, Q - 1); @@ -103,7 +124,7 @@ contract WalletTest is DSTest { address recovered = ecrecover(digest, v, r, s); assertEq(recovered, wallet.addr); } - + // tests signing a has using PK and checks the address recovered from the signautre is correct wallet address and also checks the signature is compact function testSignCompactWithWalletDigest(uint256 pkSeed, bytes32 digest) public { uint256 pk = bound(pkSeed, 1, Q - 1); @@ -125,6 +146,177 @@ contract WalletTest is DSTest { address recovered = ecrecover(digest, v, r, s); assertEq(recovered, wallet.addr); } + // signs a message after performing the checks in above functions + function testSignWithWalletMessage(uint256 pkSeed, bytes memory message) public { + testSignWithWalletDigest(pkSeed, keccak256(message)); + } + // // signs a message after performing the checks in above functions in compact way + function testSignCompactWithWalletMessage(uint256 pkSeed, bytes memory message) public { + testSignCompactWithWalletDigest(pkSeed, keccak256(message)); + } + // check sthe nonces of the wallet before and after a prank + function testGetNonceWallet(uint256 pkSeed) public { + uint256 pk = bound(pkSeed, 1, Q - 1); + + Vm.Wallet memory wallet = vm.createWallet(pk); + + uint64 nonce1 = vm.getNonce(wallet); + + vm.startPrank(wallet.addr); + new Foo(); + new Foo(); + vm.stopPrank(); + + uint64 nonce2 = vm.getNonce(wallet); + assertEq(nonce1 + 2, nonce2); + } +} + + +//////////////////////// @title A title that should describe the contract/interface +/// @author The name of the author +/// @notice Explain to an end user what this does +/// @dev Explain to a developer any extra details + + + +/ + +contract WalletTest is DSTest { + Vm constant vm = Vm(HEVM_ADDRESS); + + uint256 internal constant Q = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141; + uint256 private constant UINT256_MAX = + 115792089237316195423570985008687907853269984665640564039457584007913129639935; + + + + ParamConfig public pkConfig; + + constructor() { + pkConfig = ParamConfig({ + min: 1, + max: Q - 1, + distributionType: DistributionType.Logarithmic, + fixtures: new uint256[](0), + excluded: new uint256[](0) + }); + } + + function addressOf(uint256 x, uint256 y) internal pure returns (address) { + return address(uint160(uint256(keccak256(abi.encode(x, y))))); + } + + function bound(uint256 x, ParamConfig memory config) internal pure returns (uint256) { + if (config.distributionType == DistributionType.Logarithmic) { + return boundLog(x, config.min, config.max); + } + + require(config.min <= config.max, "min needs to be less than max"); + if (x >= config.min && x <= config.max) return x; + uint256 size = config.max - config.min + 1; + if (x <= 3 && size > x) return config.min + x; + if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) return config.max - (UINT256_MAX - x); + if (x > config.max) { + uint256 diff = x - config.max; + uint256 rem = diff % size; + if (rem == 0) return config.max; + return config.min + rem - 1; + } else if (x < config.min) { + uint256 diff = config.min - x; + uint256 rem = diff % size; + if (rem == 0) return config.min; + return config.max - rem + 1; + } + } + + function boundLog(uint256 x, uint256 min, uint256 max) internal pure returns (uint256) { + require(min < max, "min must be less than max"); + require(min > 0, "min must be greater than 0 for log distribution"); + + uint256 logMin = log2Approximation(min); + uint256 logMax = log2Approximation(max); + + uint256 logValue = bound(x, ParamConfig(logMin, logMax, DistributionType.Uniform, new uint256[](0), new uint256[](0))); + + return exp2Approximation(logValue); + } + + function log2Approximation(uint256 x) internal pure returns (uint256) { + require(x > 0, "log2 of zero is undefined"); + + uint256 n = 0; + while (x > 1) { + x >>= 1; + n++; + } + return n; + } + + function exp2Approximation(uint256 x) internal pure returns (uint256) { + if (x == 0) return 1; + + uint256 result = 2; + for (uint256 i = 1; i < x; i++) { + result *= 2; + } + return result; + } + + function testCreateWalletPrivKeyNoLabel(uint256 pkSeed) public { + uint256 pk = bound(pkSeed, pkConfig); + + Vm.Wallet memory wallet = vm.createWallet(pk); + + address expectedAddr = vm.addr(wallet.privateKey); + assertEq(expectedAddr, wallet.addr); + + expectedAddr = addressOf(wallet.publicKeyX, wallet.publicKeyY); + assertEq(expectedAddr, wallet.addr); + } + + function testCreateWalletPrivKeyWithLabel(uint256 pkSeed) public { + string memory label = "labelled wallet"; + + uint256 pk = bound(pkSeed, pkConfig); + + Vm.Wallet memory wallet = vm.createWallet(pk, label); + + address expectedAddr = vm.addr(wallet.privateKey); + assertEq(expectedAddr, wallet.addr); + + expectedAddr = addressOf(wallet.publicKeyX, wallet.publicKeyY); + assertEq(expectedAddr, wallet.addr); + + string memory expectedLabel = vm.getLabel(wallet.addr); + assertEq(expectedLabel, label, "labelled address != wallet.addr"); + } + + function testSignWithWalletDigest(uint256 pkSeed, bytes32 digest) public { + uint256 pk = bound(pkSeed, pkConfig); + + Vm.Wallet memory wallet = vm.createWallet(pk); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(wallet, digest); + + address recovered = ecrecover(digest, v, r, s); + assertEq(recovered, wallet.addr); + } + + function testSignCompactWithWalletDigest(uint256 pkSeed, bytes32 digest) public { + uint256 pk = bound(pkSeed, pkConfig); + + Vm.Wallet memory wallet = vm.createWallet(pk); + + (bytes32 r, bytes32 vs) = vm.signCompact(wallet, digest); + + bytes32 s = bytes32((uint256(vs) << 1) >> 1); + + uint8 v = uint8(uint256(vs) >> 255) + 27; + + address recovered = ecrecover(digest, v, r, s); + assertEq(recovered, wallet.addr); + } function testSignWithWalletMessage(uint256 pkSeed, bytes memory message) public { testSignWithWalletDigest(pkSeed, keccak256(message)); @@ -135,7 +327,7 @@ contract WalletTest is DSTest { } function testGetNonceWallet(uint256 pkSeed) public { - uint256 pk = bound(pkSeed, 1, Q - 1); + uint256 pk = bound(pkSeed, pkConfig); Vm.Wallet memory wallet = vm.createWallet(pk); @@ -149,4 +341,4 @@ contract WalletTest is DSTest { uint64 nonce2 = vm.getNonce(wallet); assertEq(nonce1 + 2, nonce2); } -} +} \ No newline at end of file From be4610ada7651537f9c4829d1eb83428c65e38fe Mon Sep 17 00:00:00 2001 From: Vaishnavi Singh Date: Sat, 14 Sep 2024 16:07:27 +0530 Subject: [PATCH 2/7] type func n log ranges added --- testdata/default/cheats/Wallet.t.sol | 147 +++++++++++++++++++++------ 1 file changed, 116 insertions(+), 31 deletions(-) diff --git a/testdata/default/cheats/Wallet.t.sol b/testdata/default/cheats/Wallet.t.sol index 5a7035876cd0..317d68047b41 100644 --- a/testdata/default/cheats/Wallet.t.sol +++ b/testdata/default/cheats/Wallet.t.sol @@ -7,43 +7,125 @@ import "cheats/Vm.sol"; contract Foo {} contract WalletTest is DSTest { - Vm constant vm = Vm(HEVM_ADDRESS); + Vm constant vm = Vm(HEVM_ADDRESS); // Vm contract address - uint256 internal constant Q = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141; + uint256 internal constant Q = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141; // constant acc to secp256k1 for generating PK uint256 private constant UINT256_MAX = - 115792089237316195423570985008687907853269984665640564039457584007913129639935; + 115792089237316195423570985008687907853269984665640564039457584007913129639935; // max num stored in uin256 + + enum DistributionType { Uniform, Logarithmic } // enum for the distribution type + struct ParamConfig { + uint256 min; + uint256 max; + DistributionType distributionType; + uint256[] fixtures; + uint256[] excluded; + } // struct to changes the configs and all + + ParamConfig public pkConfig; + + constructor() { + pkConfig = ParamConfig({ + min: 1, + max: Q - 1, + distributionType: DistributionType.Logarithmic, + fixtures: new uint256[](0), + excluded: new uint256[](0) + }); + } // the constructor sets the DistributionType = Logarithmic + // ask this doubt + function determineDistributionType(uint256 min, uint256 max) internal pure returns (DistributionType) { + string memory uintType = getUintType(max); + if ( + keccak256(abi.encodePacked(uintType)) == keccak256(abi.encodePacked("uint8")) || + keccak256(abi.encodePacked(uintType)) == keccak256(abi.encodePacked("uint16")) || + keccak256(abi.encodePacked(uintType)) == keccak256(abi.encodePacked("uint32"))) { + return DistributionType.Uniform; + } else { + return DistributionType.Logarithmic; + } + } + // converts Public key to Ethereum address using keccak256 hash function addressOf(uint256 x, uint256 y) internal pure returns (address) { return address(uint160(uint256(keccak256(abi.encode(x, y))))); } - function bound(uint256 x, uint256 min, uint256 max) internal pure virtual returns (uint256 result) { - require(min <= max, "min needs to be less than max"); - // If x is between min and max, return x directly. This is to ensure that dictionary values - // do not get shifted if the min is nonzero. More info: https://github.com/foundry-rs/forge-std/issues/188 - if (x >= min && x <= max) return x; + function bound(uint256 x, ParamConfig memory config)internal pure virtual returns (uint256 result) { - uint256 size = max - min + 1; + + DistributionType actualDistributionType = determineDistributionType(config.min, config.max); + if (actualDistributionType == DistributionType.Logarithmic) { + return boundLog(x, config.min, config.max); + } + require(config.min <= config.max, "min needs to be less than max"); + // If x is between min and max, return x directly. + if (x >= config.min && x <= config.max) return x; - // If the value is 0, 1, 2, 3, wrap that to min, min+1, min+2, min+3. Similarly for the UINT256_MAX side. - // This helps ensure coverage of the min/max values. - if (x <= 3 && size > x) return min + x; - if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) return max - (UINT256_MAX - x); + uint256 size = config.max - config.min + 1; + if (x <= 3 && size > x) return config.min + x; + if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) return config.max - (UINT256_MAX - x); // Otherwise, wrap x into the range [min, max], i.e. the range is inclusive. - if (x > max) { - uint256 diff = x - max; + if (x > config.max) { + uint256 diff = x - config.max; uint256 rem = diff % size; - if (rem == 0) return max; - result = min + rem - 1; - } else if (x < min) { - uint256 diff = min - x; + if (rem == 0) return config.max; + return config.min + rem - 1; + } else if (x < config.min) { + uint256 diff = config.min - x; uint256 rem = diff % size; - if (rem == 0) return min; - result = max - rem + 1; + if (rem == 0) return config.min; + return config.max - rem + 1; } } + function getUintType(uint256 value) internal pure returns(string memory) { + if(value <= type(uint8).max) return "uint8"; + if(value <= type(uint16).max) return "uint16"; + if(value <= type(uint32).max) return "uint32"; + if(value <= type(uint64).max) return "uint64"; + if(value <= type(uint128).max) return "uint128"; + if(value <= type(uint256).max) return "uint256"; + } + + + function boundLog(uint256 x, uint256 min, uint256 max) internal pure returns (uint256) { + // basic checks + require(min < max, "min must be less than max"); + require(min > 0, "min must be greater than 0 for log distribution"); + + // converts min and max to log min and max + uint256 logMin = log2Approximation(2*min); + uint256 logMax = log2Approximation(2**(max+1)-1); + + uint256 logValue = bound(x, ParamConfig(logMin, logMax, DistributionType.Uniform, new uint256[](0), new uint256[](0))); + + return exp2Approximation(logValue); + } + + function log2Approximation(uint256 x) internal pure returns (uint256) { + require(x > 0, "log2 of less than equal to zero is undefined"); + + uint256 n = 0; + while (x > 1) { + x >>= 1; + n++; + } + return n; + } + + function exp2Approximation(uint256 x) internal pure returns (uint256) { + if (x == 0) return 1; + + uint256 result = 2; + for (uint256 i = 1; i < x; i++) { + result *= 2; + } + return result; + } + + // tests that wallet is created with the address derived from PK and label is set correctly function testCreateWalletStringPrivAndLabel() public { bytes memory privKey = "this is a priv key"; Vm.Wallet memory wallet = vm.createWallet(string(privKey)); @@ -60,8 +142,9 @@ contract WalletTest is DSTest { assertEq(label, string(privKey), "labelled address != wallet.addr"); } + // tests creation of PK using a seed function testCreateWalletPrivKeyNoLabel(uint256 pkSeed) public { - uint256 pk = bound(pkSeed, 1, Q - 1); + uint256 pk = bound(pkSeed, pkConfig); Vm.Wallet memory wallet = vm.createWallet(pk); @@ -74,10 +157,12 @@ contract WalletTest is DSTest { assertEq(expectedAddr, wallet.addr); } + + // tests creation of PK using a seed and checks labels too function testCreateWalletPrivKeyWithLabel(uint256 pkSeed) public { string memory label = "labelled wallet"; - uint256 pk = bound(pkSeed, 1, Q - 1); + uint256 pk = bound(pkSeed, pkConfig); Vm.Wallet memory wallet = vm.createWallet(pk, label); @@ -92,9 +177,9 @@ contract WalletTest is DSTest { string memory expectedLabel = vm.getLabel(wallet.addr); assertEq(expectedLabel, label, "labelled address != wallet.addr"); } - + // tests signing a has using PK and checks the address recovered from the signautre is correct wallet address function testSignWithWalletDigest(uint256 pkSeed, bytes32 digest) public { - uint256 pk = bound(pkSeed, 1, Q - 1); + uint256 pk = bound(pkSeed, pkConfig); Vm.Wallet memory wallet = vm.createWallet(pk); @@ -103,9 +188,9 @@ contract WalletTest is DSTest { address recovered = ecrecover(digest, v, r, s); assertEq(recovered, wallet.addr); } - + // tests signing a has using PK and checks the address recovered from the signautre is correct wallet address and also checks the signature is compact function testSignCompactWithWalletDigest(uint256 pkSeed, bytes32 digest) public { - uint256 pk = bound(pkSeed, 1, Q - 1); + uint256 pk = bound(pkSeed, pkConfig); Vm.Wallet memory wallet = vm.createWallet(pk); @@ -125,17 +210,17 @@ contract WalletTest is DSTest { address recovered = ecrecover(digest, v, r, s); assertEq(recovered, wallet.addr); } - + // signs a message after performing the checks in above functions function testSignWithWalletMessage(uint256 pkSeed, bytes memory message) public { testSignWithWalletDigest(pkSeed, keccak256(message)); } - + // // signs a message after performing the checks in above functions in compact way function testSignCompactWithWalletMessage(uint256 pkSeed, bytes memory message) public { testSignCompactWithWalletDigest(pkSeed, keccak256(message)); } - + // check sthe nonces of the wallet before and after a prank function testGetNonceWallet(uint256 pkSeed) public { - uint256 pk = bound(pkSeed, 1, Q - 1); + uint256 pk = bound(pkSeed, pkConfig); Vm.Wallet memory wallet = vm.createWallet(pk); From 0f43841cc9e47a293f6b6e856261bc0c530f55bb Mon Sep 17 00:00:00 2001 From: Vaishnavi Singh Date: Sun, 15 Sep 2024 13:16:56 +0530 Subject: [PATCH 3/7] tye checkfunctions added --- testdata/default/cheats/Wallet.t.sol | 89 +++++++++++++++++++++------- 1 file changed, 68 insertions(+), 21 deletions(-) diff --git a/testdata/default/cheats/Wallet.t.sol b/testdata/default/cheats/Wallet.t.sol index 317d68047b41..11a1cd51bad5 100644 --- a/testdata/default/cheats/Wallet.t.sol +++ b/testdata/default/cheats/Wallet.t.sol @@ -4,6 +4,9 @@ pragma solidity 0.8.18; import "ds-test/test.sol"; import "cheats/Vm.sol"; +// make the uint type function correct +// + contract Foo {} contract WalletTest is DSTest { @@ -13,33 +16,78 @@ contract WalletTest is DSTest { uint256 private constant UINT256_MAX = 115792089237316195423570985008687907853269984665640564039457584007913129639935; // max num stored in uin256 + +// +// enums +// enum DistributionType { Uniform, Logarithmic } // enum for the distribution type + enum TypeUint {Uint8, Uint16, Uint32, Uint64, Uint128, Uint256} // enum for the uint type + +// +// structs +// struct ParamConfig { uint256 min; uint256 max; - DistributionType distributionType; - uint256[] fixtures; - uint256[] excluded; - } // struct to changes the configs and all + DistributionType distributionType; + uint256[] fixtures; + uint256[] excluded; + } // struct to changes the configs and all + + struct UintValue{ + TypeUint uintType; + TypeUint value; + } +// +// vars of structs +// ParamConfig public pkConfig; - - constructor() { + + constructor() { pkConfig = ParamConfig({ min: 1, max: Q - 1, distributionType: DistributionType.Logarithmic, fixtures: new uint256[](0), excluded: new uint256[](0) - }); + }); } // the constructor sets the DistributionType = Logarithmic - // ask this doubt + + // Separate functions for different uint types + function getUintType(uint8 value) internal pure returns (UintValue memory) { + return UintValue(TypeUint.Uint8, TypeUint(value)); + } + + function getUintType(uint16 value) internal pure returns (UintValue memory) { + return UintValue(TypeUint.Uint16, TypeUint(value)); + } + + function getUintType(uint32 value) internal pure returns (UintValue memory) { + return UintValue(TypeUint.Uint32, TypeUint(value)); + } + + function getUintType(uint64 value) internal pure returns (UintValue memory) { + return UintValue(TypeUint.Uint64, TypeUint(value)); + } + + function getUintType(uint128 value) internal pure returns (UintValue memory) { + return UintValue(TypeUint.Uint128, TypeUint(value)); + } + + function getUintType(uint256 value) internal pure returns (UintValue memory) { + return UintValue(TypeUint.Uint256, TypeUint(value)); + } + + // solve for this max and make it TypeUint type and remove the uint256 from it in the paramConfig struct function determineDistributionType(uint256 min, uint256 max) internal pure returns (DistributionType) { - string memory uintType = getUintType(max); + UintValue memory uintTypeValue = getUintType(max); if ( - keccak256(abi.encodePacked(uintType)) == keccak256(abi.encodePacked("uint8")) || - keccak256(abi.encodePacked(uintType)) == keccak256(abi.encodePacked("uint16")) || - keccak256(abi.encodePacked(uintType)) == keccak256(abi.encodePacked("uint32"))) { + keccak256(abi.encodePacked(uintTypeValue.uintType)) == keccak256(abi.encodePacked("uint8")) || + keccak256(abi.encodePacked(uintTypeValue.uintType)) == keccak256(abi.encodePacked("uint16")) || + keccak256(abi.encodePacked(uintTypeValue.uintType)) == keccak256(abi.encodePacked("uint32")) || + keccak256(abi.encodePacked(uintTypeValue.uintType)) == keccak256(abi.encodePacked("uint64")) + ) { return DistributionType.Uniform; } else { return DistributionType.Logarithmic; @@ -49,32 +97,32 @@ contract WalletTest is DSTest { // converts Public key to Ethereum address using keccak256 hash function addressOf(uint256 x, uint256 y) internal pure returns (address) { return address(uint160(uint256(keccak256(abi.encode(x, y))))); - } + } function bound(uint256 x, ParamConfig memory config)internal pure virtual returns (uint256 result) { - + DistributionType actualDistributionType = determineDistributionType(config.min, config.max); - if (actualDistributionType == DistributionType.Logarithmic) { + if (actualDistributionType == DistributionType.Logarithmic) { return boundLog(x, config.min, config.max); - } + } require(config.min <= config.max, "min needs to be less than max"); - // If x is between min and max, return x directly. + // If x is between min and max, return x directly. if (x >= config.min && x <= config.max) return x; uint256 size = config.max - config.min + 1; if (x <= 3 && size > x) return config.min + x; if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) return config.max - (UINT256_MAX - x); - // Otherwise, wrap x into the range [min, max], i.e. the range is inclusive. + // Otherwise, wrap x into the range [min, max], i.e. the range is inclusive. if (x > config.max) { uint256 diff = x - config.max; - uint256 rem = diff % size; + uint256 rem = diff % size; if (rem == 0) return config.max; return config.min + rem - 1; } else if (x < config.min) { uint256 diff = config.min - x; - uint256 rem = diff % size; + uint256 rem = diff % size; if (rem == 0) return config.min; return config.max - rem + 1; } @@ -157,7 +205,6 @@ contract WalletTest is DSTest { assertEq(expectedAddr, wallet.addr); } - // tests creation of PK using a seed and checks labels too function testCreateWalletPrivKeyWithLabel(uint256 pkSeed) public { string memory label = "labelled wallet"; From 773f1fb8ef6d3ba56eec00393f96a9e0a557f10b Mon Sep 17 00:00:00 2001 From: Vaishnavi Singh Date: Sun, 15 Sep 2024 13:23:21 +0530 Subject: [PATCH 4/7] Uint type func added --- testdata/default/cheats/Wallet.t.sol | 332 +++++++++++---------------- 1 file changed, 136 insertions(+), 196 deletions(-) diff --git a/testdata/default/cheats/Wallet.t.sol b/testdata/default/cheats/Wallet.t.sol index 96c5fac93e35..11a1cd51bad5 100644 --- a/testdata/default/cheats/Wallet.t.sol +++ b/testdata/default/cheats/Wallet.t.sol @@ -4,247 +4,157 @@ pragma solidity 0.8.18; import "ds-test/test.sol"; import "cheats/Vm.sol"; +// make the uint type function correct +// + contract Foo {} contract WalletTest is DSTest { - Vm constant vm = Vm(HEVM_ADDRESS); + Vm constant vm = Vm(HEVM_ADDRESS); // Vm contract address uint256 internal constant Q = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141; // constant acc to secp256k1 for generating PK uint256 private constant UINT256_MAX = 115792089237316195423570985008687907853269984665640564039457584007913129639935; // max num stored in uin256 - enum DistributionType { Uniform, Logarithmic } + +// +// enums +// + enum DistributionType { Uniform, Logarithmic } // enum for the distribution type + enum TypeUint {Uint8, Uint16, Uint32, Uint64, Uint128, Uint256} // enum for the uint type + +// +// structs +// struct ParamConfig { uint256 min; uint256 max; - DistributionType distributionType; - uint256[] fixtures; - uint256[] excluded; - } - - // converts Public key to Ethereum address using keccak256 hash - function addressOf(uint256 x, uint256 y) internal pure returns (address) { - return address(uint160(uint256(keccak256(abi.encode(x, y))))); - } - - function bound(uint256 x, uint256 min, uint256 max) internal pure virtual returns (uint256 result) { - require(min <= max, "min needs to be less than max"); - // If x is between min and max, return x directly. This is to ensure that dictionary values - // do not get shifted if the min is nonzero. More info: https://github.com/foundry-rs/forge-std/issues/188 - if (x >= min && x <= max) return x; - - uint256 size = max - min + 1; - - // If the value is 0, 1, 2, 3, wrap that to min, min+1, min+2, min+3. Similarly for the UINT256_MAX side. - // This helps ensure coverage of the min/max values. - if (x <= 3 && size > x) return min + x; - if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) return max - (UINT256_MAX - x); - - // Otherwise, wrap x into the range [min, max], i.e. the range is inclusive. - if (x > max) { - uint256 diff = x - max; - uint256 rem = diff % size; - if (rem == 0) return max; - result = min + rem - 1; - } else if (x < min) { - uint256 diff = min - x; - uint256 rem = diff % size; - if (rem == 0) return min; - result = max - rem + 1; - } + DistributionType distributionType; + uint256[] fixtures; + uint256[] excluded; + } // struct to changes the configs and all + + struct UintValue{ + TypeUint uintType; + TypeUint value; } +// +// vars of structs +// + ParamConfig public pkConfig; - - - - - - - - // tests that wallet is created with the address derived from PK and label is set correctly - function testCreateWalletStringPrivAndLabel() public { - bytes memory privKey = "this is a priv key"; - Vm.Wallet memory wallet = vm.createWallet(string(privKey)); - - // check wallet.addr against recovered address using private key - address expectedAddr = vm.addr(wallet.privateKey); - assertEq(expectedAddr, wallet.addr); - - // check wallet.addr against recovered address using x and y coordinates - expectedAddr = addressOf(wallet.publicKeyX, wallet.publicKeyY); - assertEq(expectedAddr, wallet.addr); - - string memory label = vm.getLabel(wallet.addr); - assertEq(label, string(privKey), "labelled address != wallet.addr"); + constructor() { + pkConfig = ParamConfig({ + min: 1, + max: Q - 1, + distributionType: DistributionType.Logarithmic, + fixtures: new uint256[](0), + excluded: new uint256[](0) + }); + } // the constructor sets the DistributionType = Logarithmic + + // Separate functions for different uint types + function getUintType(uint8 value) internal pure returns (UintValue memory) { + return UintValue(TypeUint.Uint8, TypeUint(value)); } - // tests creation of PK using a seed - function testCreateWalletPrivKeyNoLabel(uint256 pkSeed) public { - uint256 pk = bound(pkSeed, 1, Q - 1); - - Vm.Wallet memory wallet = vm.createWallet(pk); - - // check wallet.addr against recovered address using private key - address expectedAddr = vm.addr(wallet.privateKey); - assertEq(expectedAddr, wallet.addr); - - // check wallet.addr against recovered address using x and y coordinates - expectedAddr = addressOf(wallet.publicKeyX, wallet.publicKeyY); - assertEq(expectedAddr, wallet.addr); + function getUintType(uint16 value) internal pure returns (UintValue memory) { + return UintValue(TypeUint.Uint16, TypeUint(value)); } - // tests creation of PK using a seed and checks labels too - function testCreateWalletPrivKeyWithLabel(uint256 pkSeed) public { - string memory label = "labelled wallet"; - - uint256 pk = bound(pkSeed, 1, Q - 1); - - Vm.Wallet memory wallet = vm.createWallet(pk, label); - - // check wallet.addr against recovered address using private key - address expectedAddr = vm.addr(wallet.privateKey); - assertEq(expectedAddr, wallet.addr); - - // check wallet.addr against recovered address using x and y coordinates - expectedAddr = addressOf(wallet.publicKeyX, wallet.publicKeyY); - assertEq(expectedAddr, wallet.addr); - - string memory expectedLabel = vm.getLabel(wallet.addr); - assertEq(expectedLabel, label, "labelled address != wallet.addr"); + function getUintType(uint32 value) internal pure returns (UintValue memory) { + return UintValue(TypeUint.Uint32, TypeUint(value)); } - // tests signing a has using PK and checks the address recovered from the signautre is correct wallet address - function testSignWithWalletDigest(uint256 pkSeed, bytes32 digest) public { - uint256 pk = bound(pkSeed, 1, Q - 1); - - Vm.Wallet memory wallet = vm.createWallet(pk); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(wallet, digest); - - address recovered = ecrecover(digest, v, r, s); - assertEq(recovered, wallet.addr); + function getUintType(uint64 value) internal pure returns (UintValue memory) { + return UintValue(TypeUint.Uint64, TypeUint(value)); } - // tests signing a has using PK and checks the address recovered from the signautre is correct wallet address and also checks the signature is compact - function testSignCompactWithWalletDigest(uint256 pkSeed, bytes32 digest) public { - uint256 pk = bound(pkSeed, 1, Q - 1); - - Vm.Wallet memory wallet = vm.createWallet(pk); - - (bytes32 r, bytes32 vs) = vm.signCompact(wallet, digest); - - // Extract `s` from `vs`. - // Shift left by 1 bit to clear the leftmost bit, then shift right by 1 bit to restore the original position. - // This effectively clears the leftmost bit of `vs`, giving us `s`. - bytes32 s = bytes32((uint256(vs) << 1) >> 1); - - // Extract `v` from `vs`. - // We shift `vs` right by 255 bits to isolate the leftmost bit. - // Converting this to uint8 gives us the parity bit (0 or 1). - // Adding 27 converts this parity bit to the correct `v` value (27 or 28). - uint8 v = uint8(uint256(vs) >> 255) + 27; - address recovered = ecrecover(digest, v, r, s); - assertEq(recovered, wallet.addr); - } - // signs a message after performing the checks in above functions - function testSignWithWalletMessage(uint256 pkSeed, bytes memory message) public { - testSignWithWalletDigest(pkSeed, keccak256(message)); - } - // // signs a message after performing the checks in above functions in compact way - function testSignCompactWithWalletMessage(uint256 pkSeed, bytes memory message) public { - testSignCompactWithWalletDigest(pkSeed, keccak256(message)); + function getUintType(uint128 value) internal pure returns (UintValue memory) { + return UintValue(TypeUint.Uint128, TypeUint(value)); } - // check sthe nonces of the wallet before and after a prank - function testGetNonceWallet(uint256 pkSeed) public { - uint256 pk = bound(pkSeed, 1, Q - 1); - - Vm.Wallet memory wallet = vm.createWallet(pk); - - uint64 nonce1 = vm.getNonce(wallet); - vm.startPrank(wallet.addr); - new Foo(); - new Foo(); - vm.stopPrank(); - - uint64 nonce2 = vm.getNonce(wallet); - assertEq(nonce1 + 2, nonce2); + function getUintType(uint256 value) internal pure returns (UintValue memory) { + return UintValue(TypeUint.Uint256, TypeUint(value)); } -} - - -//////////////////////// @title A title that should describe the contract/interface -/// @author The name of the author -/// @notice Explain to an end user what this does -/// @dev Explain to a developer any extra details - - -/ - -contract WalletTest is DSTest { - Vm constant vm = Vm(HEVM_ADDRESS); - - uint256 internal constant Q = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141; - uint256 private constant UINT256_MAX = - 115792089237316195423570985008687907853269984665640564039457584007913129639935; - - - - ParamConfig public pkConfig; - - constructor() { - pkConfig = ParamConfig({ - min: 1, - max: Q - 1, - distributionType: DistributionType.Logarithmic, - fixtures: new uint256[](0), - excluded: new uint256[](0) - }); + // solve for this max and make it TypeUint type and remove the uint256 from it in the paramConfig struct + function determineDistributionType(uint256 min, uint256 max) internal pure returns (DistributionType) { + UintValue memory uintTypeValue = getUintType(max); + if ( + keccak256(abi.encodePacked(uintTypeValue.uintType)) == keccak256(abi.encodePacked("uint8")) || + keccak256(abi.encodePacked(uintTypeValue.uintType)) == keccak256(abi.encodePacked("uint16")) || + keccak256(abi.encodePacked(uintTypeValue.uintType)) == keccak256(abi.encodePacked("uint32")) || + keccak256(abi.encodePacked(uintTypeValue.uintType)) == keccak256(abi.encodePacked("uint64")) + ) { + return DistributionType.Uniform; + } else { + return DistributionType.Logarithmic; + } } + // converts Public key to Ethereum address using keccak256 hash function addressOf(uint256 x, uint256 y) internal pure returns (address) { return address(uint160(uint256(keccak256(abi.encode(x, y))))); - } + } - function bound(uint256 x, ParamConfig memory config) internal pure returns (uint256) { - if (config.distributionType == DistributionType.Logarithmic) { + function bound(uint256 x, ParamConfig memory config)internal pure virtual returns (uint256 result) { + + + DistributionType actualDistributionType = determineDistributionType(config.min, config.max); + if (actualDistributionType == DistributionType.Logarithmic) { return boundLog(x, config.min, config.max); - } - - require(config.min <= config.max, "min needs to be less than max"); - if (x >= config.min && x <= config.max) return x; - uint256 size = config.max - config.min + 1; + } + require(config.min <= config.max, "min needs to be less than max"); + // If x is between min and max, return x directly. + if (x >= config.min && x <= config.max) return x; + + uint256 size = config.max - config.min + 1; if (x <= 3 && size > x) return config.min + x; if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) return config.max - (UINT256_MAX - x); + + // Otherwise, wrap x into the range [min, max], i.e. the range is inclusive. if (x > config.max) { uint256 diff = x - config.max; - uint256 rem = diff % size; + uint256 rem = diff % size; if (rem == 0) return config.max; return config.min + rem - 1; } else if (x < config.min) { uint256 diff = config.min - x; - uint256 rem = diff % size; + uint256 rem = diff % size; if (rem == 0) return config.min; return config.max - rem + 1; } } - function boundLog(uint256 x, uint256 min, uint256 max) internal pure returns (uint256) { + function getUintType(uint256 value) internal pure returns(string memory) { + if(value <= type(uint8).max) return "uint8"; + if(value <= type(uint16).max) return "uint16"; + if(value <= type(uint32).max) return "uint32"; + if(value <= type(uint64).max) return "uint64"; + if(value <= type(uint128).max) return "uint128"; + if(value <= type(uint256).max) return "uint256"; + } + + + function boundLog(uint256 x, uint256 min, uint256 max) internal pure returns (uint256) { + // basic checks require(min < max, "min must be less than max"); require(min > 0, "min must be greater than 0 for log distribution"); - uint256 logMin = log2Approximation(min); - uint256 logMax = log2Approximation(max); + // converts min and max to log min and max + uint256 logMin = log2Approximation(2*min); + uint256 logMax = log2Approximation(2**(max+1)-1); uint256 logValue = bound(x, ParamConfig(logMin, logMax, DistributionType.Uniform, new uint256[](0), new uint256[](0))); return exp2Approximation(logValue); } - function log2Approximation(uint256 x) internal pure returns (uint256) { - require(x > 0, "log2 of zero is undefined"); - + function log2Approximation(uint256 x) internal pure returns (uint256) { + require(x > 0, "log2 of less than equal to zero is undefined"); + uint256 n = 0; while (x > 1) { x >>= 1; @@ -263,18 +173,39 @@ contract WalletTest is DSTest { return result; } + // tests that wallet is created with the address derived from PK and label is set correctly + function testCreateWalletStringPrivAndLabel() public { + bytes memory privKey = "this is a priv key"; + Vm.Wallet memory wallet = vm.createWallet(string(privKey)); + + // check wallet.addr against recovered address using private key + address expectedAddr = vm.addr(wallet.privateKey); + assertEq(expectedAddr, wallet.addr); + + // check wallet.addr against recovered address using x and y coordinates + expectedAddr = addressOf(wallet.publicKeyX, wallet.publicKeyY); + assertEq(expectedAddr, wallet.addr); + + string memory label = vm.getLabel(wallet.addr); + assertEq(label, string(privKey), "labelled address != wallet.addr"); + } + + // tests creation of PK using a seed function testCreateWalletPrivKeyNoLabel(uint256 pkSeed) public { uint256 pk = bound(pkSeed, pkConfig); Vm.Wallet memory wallet = vm.createWallet(pk); + // check wallet.addr against recovered address using private key address expectedAddr = vm.addr(wallet.privateKey); assertEq(expectedAddr, wallet.addr); + // check wallet.addr against recovered address using x and y coordinates expectedAddr = addressOf(wallet.publicKeyX, wallet.publicKeyY); assertEq(expectedAddr, wallet.addr); } + // tests creation of PK using a seed and checks labels too function testCreateWalletPrivKeyWithLabel(uint256 pkSeed) public { string memory label = "labelled wallet"; @@ -282,18 +213,20 @@ contract WalletTest is DSTest { Vm.Wallet memory wallet = vm.createWallet(pk, label); + // check wallet.addr against recovered address using private key address expectedAddr = vm.addr(wallet.privateKey); assertEq(expectedAddr, wallet.addr); + // check wallet.addr against recovered address using x and y coordinates expectedAddr = addressOf(wallet.publicKeyX, wallet.publicKeyY); assertEq(expectedAddr, wallet.addr); string memory expectedLabel = vm.getLabel(wallet.addr); assertEq(expectedLabel, label, "labelled address != wallet.addr"); } - + // tests signing a has using PK and checks the address recovered from the signautre is correct wallet address function testSignWithWalletDigest(uint256 pkSeed, bytes32 digest) public { - uint256 pk = bound(pkSeed, pkConfig); + uint256 pk = bound(pkSeed, pkConfig); Vm.Wallet memory wallet = vm.createWallet(pk); @@ -302,32 +235,39 @@ contract WalletTest is DSTest { address recovered = ecrecover(digest, v, r, s); assertEq(recovered, wallet.addr); } - + // tests signing a has using PK and checks the address recovered from the signautre is correct wallet address and also checks the signature is compact function testSignCompactWithWalletDigest(uint256 pkSeed, bytes32 digest) public { - uint256 pk = bound(pkSeed, pkConfig); + uint256 pk = bound(pkSeed, pkConfig); Vm.Wallet memory wallet = vm.createWallet(pk); (bytes32 r, bytes32 vs) = vm.signCompact(wallet, digest); + // Extract `s` from `vs`. + // Shift left by 1 bit to clear the leftmost bit, then shift right by 1 bit to restore the original position. + // This effectively clears the leftmost bit of `vs`, giving us `s`. bytes32 s = bytes32((uint256(vs) << 1) >> 1); + // Extract `v` from `vs`. + // We shift `vs` right by 255 bits to isolate the leftmost bit. + // Converting this to uint8 gives us the parity bit (0 or 1). + // Adding 27 converts this parity bit to the correct `v` value (27 or 28). uint8 v = uint8(uint256(vs) >> 255) + 27; address recovered = ecrecover(digest, v, r, s); assertEq(recovered, wallet.addr); } - + // signs a message after performing the checks in above functions function testSignWithWalletMessage(uint256 pkSeed, bytes memory message) public { testSignWithWalletDigest(pkSeed, keccak256(message)); } - + // // signs a message after performing the checks in above functions in compact way function testSignCompactWithWalletMessage(uint256 pkSeed, bytes memory message) public { testSignCompactWithWalletDigest(pkSeed, keccak256(message)); } - + // check sthe nonces of the wallet before and after a prank function testGetNonceWallet(uint256 pkSeed) public { - uint256 pk = bound(pkSeed, pkConfig); + uint256 pk = bound(pkSeed, pkConfig); Vm.Wallet memory wallet = vm.createWallet(pk); @@ -341,4 +281,4 @@ contract WalletTest is DSTest { uint64 nonce2 = vm.getNonce(wallet); assertEq(nonce1 + 2, nonce2); } -} \ No newline at end of file +} From 8c7c9c43caa6054dff789458e867e297e09fd4c6 Mon Sep 17 00:00:00 2001 From: Vaishnavi Singh Date: Sun, 15 Sep 2024 13:35:02 +0530 Subject: [PATCH 5/7] Trigger GitHub to update contribution graph From ade0875b90330be99977532f7371139839841641 Mon Sep 17 00:00:00 2001 From: Vaishnavi Singh Date: Mon, 16 Sep 2024 16:34:42 +0530 Subject: [PATCH 6/7] TypeUint added to bound and boundLog --- testdata/default/cheats/Wallet.t.sol | 161 ++++++++++++--------------- 1 file changed, 70 insertions(+), 91 deletions(-) diff --git a/testdata/default/cheats/Wallet.t.sol b/testdata/default/cheats/Wallet.t.sol index 11a1cd51bad5..210b90db6538 100644 --- a/testdata/default/cheats/Wallet.t.sol +++ b/testdata/default/cheats/Wallet.t.sol @@ -4,8 +4,6 @@ pragma solidity 0.8.18; import "ds-test/test.sol"; import "cheats/Vm.sol"; -// make the uint type function correct -// contract Foo {} @@ -17,18 +15,13 @@ contract WalletTest is DSTest { 115792089237316195423570985008687907853269984665640564039457584007913129639935; // max num stored in uin256 -// -// enums -// + enum DistributionType { Uniform, Logarithmic } // enum for the distribution type enum TypeUint {Uint8, Uint16, Uint32, Uint64, Uint128, Uint256} // enum for the uint type -// -// structs -// struct ParamConfig { uint256 min; - uint256 max; + TypeUint max; DistributionType distributionType; uint256[] fixtures; uint256[] excluded; @@ -39,15 +32,12 @@ contract WalletTest is DSTest { TypeUint value; } -// -// vars of structs -// ParamConfig public pkConfig; constructor() { pkConfig = ParamConfig({ min: 1, - max: Q - 1, + max: TypeUint(Q - 1), distributionType: DistributionType.Logarithmic, fixtures: new uint256[](0), excluded: new uint256[](0) @@ -55,39 +45,28 @@ contract WalletTest is DSTest { } // the constructor sets the DistributionType = Logarithmic // Separate functions for different uint types - function getUintType(uint8 value) internal pure returns (UintValue memory) { - return UintValue(TypeUint.Uint8, TypeUint(value)); - } - - function getUintType(uint16 value) internal pure returns (UintValue memory) { - return UintValue(TypeUint.Uint16, TypeUint(value)); - } - - function getUintType(uint32 value) internal pure returns (UintValue memory) { - return UintValue(TypeUint.Uint32, TypeUint(value)); - } - - function getUintType(uint64 value) internal pure returns (UintValue memory) { - return UintValue(TypeUint.Uint64, TypeUint(value)); - } - - function getUintType(uint128 value) internal pure returns (UintValue memory) { - return UintValue(TypeUint.Uint128, TypeUint(value)); - } - - function getUintType(uint256 value) internal pure returns (UintValue memory) { - return UintValue(TypeUint.Uint256, TypeUint(value)); - } + function getUintType(uint8 value) internal pure returns (UintValue memory) { + return UintValue(TypeUint.Uint8, TypeUint(value)); +} +function getUintType(uint16 value) internal pure returns (UintValue memory) { + return UintValue(TypeUint.Uint16, TypeUint(value)); +} +function getUintType(uint32 value) internal pure returns (UintValue memory) { + return UintValue(TypeUint.Uint32, TypeUint(value)); +} +function getUintType(uint64 value) internal pure returns (UintValue memory) { + return UintValue(TypeUint.Uint64, TypeUint(value)); +} +function getUintType(uint128 value) internal pure returns (UintValue memory) { + return UintValue(TypeUint.Uint128, TypeUint(value)); +} +function getUintType(uint256 value) internal pure returns (UintValue memory) { + return UintValue(TypeUint.Uint256, TypeUint(value)); +} // solve for this max and make it TypeUint type and remove the uint256 from it in the paramConfig struct - function determineDistributionType(uint256 min, uint256 max) internal pure returns (DistributionType) { - UintValue memory uintTypeValue = getUintType(max); - if ( - keccak256(abi.encodePacked(uintTypeValue.uintType)) == keccak256(abi.encodePacked("uint8")) || - keccak256(abi.encodePacked(uintTypeValue.uintType)) == keccak256(abi.encodePacked("uint16")) || - keccak256(abi.encodePacked(uintTypeValue.uintType)) == keccak256(abi.encodePacked("uint32")) || - keccak256(abi.encodePacked(uintTypeValue.uintType)) == keccak256(abi.encodePacked("uint64")) - ) { + function determineDistributionType(uint256 min, TypeUint max) internal pure returns (DistributionType) { + if (max == TypeUint.Uint8 || max == TypeUint.Uint16 || max == TypeUint.Uint32 || max == TypeUint.Uint64) { return DistributionType.Uniform; } else { return DistributionType.Logarithmic; @@ -99,60 +78,51 @@ contract WalletTest is DSTest { return address(uint160(uint256(keccak256(abi.encode(x, y))))); } - function bound(uint256 x, ParamConfig memory config)internal pure virtual returns (uint256 result) { - + function getMaxValueForType(TypeUint uintType) internal pure returns (uint256) { + if (uintType == TypeUint.Uint8) return type(uint8).max; + if (uintType == TypeUint.Uint16) return type(uint16).max; + if (uintType == TypeUint.Uint32) return type(uint32).max; + if (uintType == TypeUint.Uint64) return type(uint64).max; + if (uintType == TypeUint.Uint128) return type(uint128).max; + return type(uint256).max; + } - DistributionType actualDistributionType = determineDistributionType(config.min, config.max); + function bound(uint256 x, ParamConfig memory config) internal pure virtual returns (uint256 result) { + uint256 maxValue = getMaxValueForType(config.max); + DistributionType actualDistributionType = determineDistributionType(config.min, config.max); + if (actualDistributionType == DistributionType.Logarithmic) { - return boundLog(x, config.min, config.max); + return boundLog(x, config.min, config.max); } - require(config.min <= config.max, "min needs to be less than max"); - // If x is between min and max, return x directly. - if (x >= config.min && x <= config.max) return x; - - uint256 size = config.max - config.min + 1; - if (x <= 3 && size > x) return config.min + x; - if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) return config.max - (UINT256_MAX - x); - - // Otherwise, wrap x into the range [min, max], i.e. the range is inclusive. - if (x > config.max) { - uint256 diff = x - config.max; + require(config.min <= maxValue, "min needs to be less than max"); + if (x >= config.min && x <= maxValue) return x; + uint256 size = maxValue - config.min + 1; + if (x <= 3 && size > x) return config.min + x; + if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) return maxValue - (UINT256_MAX - x); + if (x > maxValue) { + uint256 diff = x - maxValue; uint256 rem = diff % size; - if (rem == 0) return config.max; - return config.min + rem - 1; - } else if (x < config.min) { - uint256 diff = config.min - x; + if (rem == 0) return maxValue; + return config.min + rem - 1; + } else if (x < config.min) { + uint256 diff = config.min - x; uint256 rem = diff % size; - if (rem == 0) return config.min; - return config.max - rem + 1; - } + if (rem == 0) return config.min; + return maxValue - rem + 1; } +} - function getUintType(uint256 value) internal pure returns(string memory) { - if(value <= type(uint8).max) return "uint8"; - if(value <= type(uint16).max) return "uint16"; - if(value <= type(uint32).max) return "uint32"; - if(value <= type(uint64).max) return "uint64"; - if(value <= type(uint128).max) return "uint128"; - if(value <= type(uint256).max) return "uint256"; - } - - - function boundLog(uint256 x, uint256 min, uint256 max) internal pure returns (uint256) { - // basic checks - require(min < max, "min must be less than max"); - require(min > 0, "min must be greater than 0 for log distribution"); - - // converts min and max to log min and max - uint256 logMin = log2Approximation(2*min); - uint256 logMax = log2Approximation(2**(max+1)-1); - - uint256 logValue = bound(x, ParamConfig(logMin, logMax, DistributionType.Uniform, new uint256[](0), new uint256[](0))); - - return exp2Approximation(logValue); - } +function boundLog(uint256 x, uint256 min, TypeUint max) internal pure returns (uint256) { + require(min > 0, "min must be greater than 0 for log distribution"); + uint256 maxValue = getMaxValueForType(max); + require(min < maxValue, "min must be less than max"); + uint256 logMin = log2Approximation(2*min); + uint256 logMax = log2Approximation(2**(maxValue+1)-1); + uint256 logValue = bound(x, ParamConfig(logMin, TypeUint.Uint256, DistributionType.Uniform, new uint256[](0), new uint256[](0))); + return exp2Approximation(logValue); +} - function log2Approximation(uint256 x) internal pure returns (uint256) { + function log2Approximation(uint256 x) internal pure returns (uint256) { require(x > 0, "log2 of less than equal to zero is undefined"); uint256 n = 0; @@ -171,8 +141,17 @@ contract WalletTest is DSTest { result *= 2; } return result; - } + } + function getUintType(uint256 value) internal pure returns(string memory) { + if(value <= type(uint8).max) return "uint8"; + if(value <= type(uint16).max) return "uint16"; + if(value <= type(uint32).max) return "uint32"; + if(value <= type(uint64).max) return "uint64"; + if(value <= type(uint128).max) return "uint128"; + if(value <= type(uint256).max) return "uint256"; + } + // tests that wallet is created with the address derived from PK and label is set correctly function testCreateWalletStringPrivAndLabel() public { bytes memory privKey = "this is a priv key"; From 119853b6f78183ee8bd84b6399334bb338e1d2dd Mon Sep 17 00:00:00 2001 From: Vaishnavi Singh Date: Mon, 16 Sep 2024 16:47:58 +0530 Subject: [PATCH 7/7] linted --- testdata/default/cheats/Wallet.t.sol | 241 +++++++++++++++++---------- 1 file changed, 149 insertions(+), 92 deletions(-) diff --git a/testdata/default/cheats/Wallet.t.sol b/testdata/default/cheats/Wallet.t.sol index 210b90db6538..44330cf942f8 100644 --- a/testdata/default/cheats/Wallet.t.sol +++ b/testdata/default/cheats/Wallet.t.sol @@ -4,37 +4,45 @@ pragma solidity 0.8.18; import "ds-test/test.sol"; import "cheats/Vm.sol"; - contract Foo {} contract WalletTest is DSTest { - Vm constant vm = Vm(HEVM_ADDRESS); // Vm contract address + Vm constant vm = Vm(HEVM_ADDRESS); // Vm contract address - uint256 internal constant Q = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141; // constant acc to secp256k1 for generating PK + uint256 internal constant Q = + 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141; // constant acc to secp256k1 for generating PK uint256 private constant UINT256_MAX = 115792089237316195423570985008687907853269984665640564039457584007913129639935; // max num stored in uin256 - - - enum DistributionType { Uniform, Logarithmic } // enum for the distribution type - enum TypeUint {Uint8, Uint16, Uint32, Uint64, Uint128, Uint256} // enum for the uint type + enum DistributionType { + Uniform, + Logarithmic + } // enum for the distribution type + enum TypeUint { + Uint8, + Uint16, + Uint32, + Uint64, + Uint128, + Uint256 + } // enum for the uint type struct ParamConfig { uint256 min; TypeUint max; - DistributionType distributionType; - uint256[] fixtures; - uint256[] excluded; - } // struct to changes the configs and all + DistributionType distributionType; + uint256[] fixtures; + uint256[] excluded; + } // struct to changes the configs and all - struct UintValue{ + struct UintValue { TypeUint uintType; TypeUint value; } ParamConfig public pkConfig; - - constructor() { + + constructor() { pkConfig = ParamConfig({ min: 1, max: TypeUint(Q - 1), @@ -42,31 +50,49 @@ contract WalletTest is DSTest { fixtures: new uint256[](0), excluded: new uint256[](0) }); - } // the constructor sets the DistributionType = Logarithmic - - // Separate functions for different uint types - function getUintType(uint8 value) internal pure returns (UintValue memory) { - return UintValue(TypeUint.Uint8, TypeUint(value)); -} -function getUintType(uint16 value) internal pure returns (UintValue memory) { - return UintValue(TypeUint.Uint16, TypeUint(value)); -} -function getUintType(uint32 value) internal pure returns (UintValue memory) { - return UintValue(TypeUint.Uint32, TypeUint(value)); -} -function getUintType(uint64 value) internal pure returns (UintValue memory) { - return UintValue(TypeUint.Uint64, TypeUint(value)); -} -function getUintType(uint128 value) internal pure returns (UintValue memory) { - return UintValue(TypeUint.Uint128, TypeUint(value)); -} -function getUintType(uint256 value) internal pure returns (UintValue memory) { - return UintValue(TypeUint.Uint256, TypeUint(value)); -} + } // the constructor sets the DistributionType = Logarithmic + + // Separate functions for different uint types + function getUintType(uint8 value) internal pure returns (UintValue memory) { + return UintValue(TypeUint.Uint8, TypeUint(value)); + } + function getUintType( + uint16 value + ) internal pure returns (UintValue memory) { + return UintValue(TypeUint.Uint16, TypeUint(value)); + } + function getUintType( + uint32 value + ) internal pure returns (UintValue memory) { + return UintValue(TypeUint.Uint32, TypeUint(value)); + } + function getUintType( + uint64 value + ) internal pure returns (UintValue memory) { + return UintValue(TypeUint.Uint64, TypeUint(value)); + } + function getUintType( + uint128 value + ) internal pure returns (UintValue memory) { + return UintValue(TypeUint.Uint128, TypeUint(value)); + } + function getUintType( + uint256 value + ) internal pure returns (UintValue memory) { + return UintValue(TypeUint.Uint256, TypeUint(value)); + } - // solve for this max and make it TypeUint type and remove the uint256 from it in the paramConfig struct - function determineDistributionType(uint256 min, TypeUint max) internal pure returns (DistributionType) { - if (max == TypeUint.Uint8 || max == TypeUint.Uint16 || max == TypeUint.Uint32 || max == TypeUint.Uint64) { + // solve for this max and make it TypeUint type and remove the uint256 from it in the paramConfig struct + function determineDistributionType( + uint256 min, + TypeUint max + ) internal pure returns (DistributionType) { + if ( + max == TypeUint.Uint8 || + max == TypeUint.Uint16 || + max == TypeUint.Uint32 || + max == TypeUint.Uint64 + ) { return DistributionType.Uniform; } else { return DistributionType.Logarithmic; @@ -76,9 +102,11 @@ function getUintType(uint256 value) internal pure returns (UintValue memory) { // converts Public key to Ethereum address using keccak256 hash function addressOf(uint256 x, uint256 y) internal pure returns (address) { return address(uint160(uint256(keccak256(abi.encode(x, y))))); - } + } - function getMaxValueForType(TypeUint uintType) internal pure returns (uint256) { + function getMaxValueForType( + TypeUint uintType + ) internal pure returns (uint256) { if (uintType == TypeUint.Uint8) return type(uint8).max; if (uintType == TypeUint.Uint16) return type(uint16).max; if (uintType == TypeUint.Uint32) return type(uint32).max; @@ -87,44 +115,64 @@ function getUintType(uint256 value) internal pure returns (UintValue memory) { return type(uint256).max; } - function bound(uint256 x, ParamConfig memory config) internal pure virtual returns (uint256 result) { - uint256 maxValue = getMaxValueForType(config.max); - DistributionType actualDistributionType = determineDistributionType(config.min, config.max); - - if (actualDistributionType == DistributionType.Logarithmic) { - return boundLog(x, config.min, config.max); - } - require(config.min <= maxValue, "min needs to be less than max"); - if (x >= config.min && x <= maxValue) return x; - uint256 size = maxValue - config.min + 1; - if (x <= 3 && size > x) return config.min + x; - if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) return maxValue - (UINT256_MAX - x); - if (x > maxValue) { - uint256 diff = x - maxValue; - uint256 rem = diff % size; - if (rem == 0) return maxValue; - return config.min + rem - 1; - } else if (x < config.min) { - uint256 diff = config.min - x; - uint256 rem = diff % size; - if (rem == 0) return config.min; - return maxValue - rem + 1; + function bound( + uint256 x, + ParamConfig memory config + ) internal pure virtual returns (uint256 result) { + uint256 maxValue = getMaxValueForType(config.max); + DistributionType actualDistributionType = determineDistributionType( + config.min, + config.max + ); + + if (actualDistributionType == DistributionType.Logarithmic) { + return boundLog(x, config.min, config.max); + } + require(config.min <= maxValue, "min needs to be less than max"); + if (x >= config.min && x <= maxValue) return x; + uint256 size = maxValue - config.min + 1; + if (x <= 3 && size > x) return config.min + x; + if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) + return maxValue - (UINT256_MAX - x); + if (x > maxValue) { + uint256 diff = x - maxValue; + uint256 rem = diff % size; + if (rem == 0) return maxValue; + return config.min + rem - 1; + } else if (x < config.min) { + uint256 diff = config.min - x; + uint256 rem = diff % size; + if (rem == 0) return config.min; + return maxValue - rem + 1; + } } -} -function boundLog(uint256 x, uint256 min, TypeUint max) internal pure returns (uint256) { - require(min > 0, "min must be greater than 0 for log distribution"); - uint256 maxValue = getMaxValueForType(max); - require(min < maxValue, "min must be less than max"); - uint256 logMin = log2Approximation(2*min); - uint256 logMax = log2Approximation(2**(maxValue+1)-1); - uint256 logValue = bound(x, ParamConfig(logMin, TypeUint.Uint256, DistributionType.Uniform, new uint256[](0), new uint256[](0))); - return exp2Approximation(logValue); -} + function boundLog( + uint256 x, + uint256 min, + TypeUint max + ) internal pure returns (uint256) { + require(min > 0, "min must be greater than 0 for log distribution"); + uint256 maxValue = getMaxValueForType(max); + require(min < maxValue, "min must be less than max"); + uint256 logMin = log2Approximation(2 * min); + uint256 logMax = log2Approximation(2 ** (maxValue + 1) - 1); + uint256 logValue = bound( + x, + ParamConfig( + logMin, + TypeUint.Uint256, + DistributionType.Uniform, + new uint256[](0), + new uint256[](0) + ) + ); + return exp2Approximation(logValue); + } function log2Approximation(uint256 x) internal pure returns (uint256) { require(x > 0, "log2 of less than equal to zero is undefined"); - + uint256 n = 0; while (x > 1) { x >>= 1; @@ -135,23 +183,23 @@ function boundLog(uint256 x, uint256 min, TypeUint max) internal pure returns (u function exp2Approximation(uint256 x) internal pure returns (uint256) { if (x == 0) return 1; - + uint256 result = 2; for (uint256 i = 1; i < x; i++) { result *= 2; } return result; - } - - function getUintType(uint256 value) internal pure returns(string memory) { - if(value <= type(uint8).max) return "uint8"; - if(value <= type(uint16).max) return "uint16"; - if(value <= type(uint32).max) return "uint32"; - if(value <= type(uint64).max) return "uint64"; - if(value <= type(uint128).max) return "uint128"; - if(value <= type(uint256).max) return "uint256"; } - + + function getUintType(uint256 value) internal pure returns (string memory) { + if (value <= type(uint8).max) return "uint8"; + if (value <= type(uint16).max) return "uint16"; + if (value <= type(uint32).max) return "uint32"; + if (value <= type(uint64).max) return "uint64"; + if (value <= type(uint128).max) return "uint128"; + if (value <= type(uint256).max) return "uint256"; + } + // tests that wallet is created with the address derived from PK and label is set correctly function testCreateWalletStringPrivAndLabel() public { bytes memory privKey = "this is a priv key"; @@ -184,7 +232,7 @@ function boundLog(uint256 x, uint256 min, TypeUint max) internal pure returns (u assertEq(expectedAddr, wallet.addr); } - // tests creation of PK using a seed and checks labels too + // tests creation of PK using a seed and checks labels too function testCreateWalletPrivKeyWithLabel(uint256 pkSeed) public { string memory label = "labelled wallet"; @@ -205,7 +253,7 @@ function boundLog(uint256 x, uint256 min, TypeUint max) internal pure returns (u } // tests signing a has using PK and checks the address recovered from the signautre is correct wallet address function testSignWithWalletDigest(uint256 pkSeed, bytes32 digest) public { - uint256 pk = bound(pkSeed, pkConfig); + uint256 pk = bound(pkSeed, pkConfig); Vm.Wallet memory wallet = vm.createWallet(pk); @@ -215,8 +263,11 @@ function boundLog(uint256 x, uint256 min, TypeUint max) internal pure returns (u assertEq(recovered, wallet.addr); } // tests signing a has using PK and checks the address recovered from the signautre is correct wallet address and also checks the signature is compact - function testSignCompactWithWalletDigest(uint256 pkSeed, bytes32 digest) public { - uint256 pk = bound(pkSeed, pkConfig); + function testSignCompactWithWalletDigest( + uint256 pkSeed, + bytes32 digest + ) public { + uint256 pk = bound(pkSeed, pkConfig); Vm.Wallet memory wallet = vm.createWallet(pk); @@ -237,16 +288,22 @@ function boundLog(uint256 x, uint256 min, TypeUint max) internal pure returns (u assertEq(recovered, wallet.addr); } // signs a message after performing the checks in above functions - function testSignWithWalletMessage(uint256 pkSeed, bytes memory message) public { + function testSignWithWalletMessage( + uint256 pkSeed, + bytes memory message + ) public { testSignWithWalletDigest(pkSeed, keccak256(message)); } - // // signs a message after performing the checks in above functions in compact way - function testSignCompactWithWalletMessage(uint256 pkSeed, bytes memory message) public { + // // signs a message after performing the checks in above functions in compact way + function testSignCompactWithWalletMessage( + uint256 pkSeed, + bytes memory message + ) public { testSignCompactWithWalletDigest(pkSeed, keccak256(message)); } // check sthe nonces of the wallet before and after a prank function testGetNonceWallet(uint256 pkSeed) public { - uint256 pk = bound(pkSeed, pkConfig); + uint256 pk = bound(pkSeed, pkConfig); Vm.Wallet memory wallet = vm.createWallet(pk);