diff --git a/foundry_test/modules/utils/L2CompressorHuffReadFlag.t.sol b/foundry_test/modules/utils/L2CompressorHuffReadFlag.t.sol index 3e438b2..4ec4618 100644 --- a/foundry_test/modules/utils/L2CompressorHuffReadFlag.t.sol +++ b/foundry_test/modules/utils/L2CompressorHuffReadFlag.t.sol @@ -25,19 +25,6 @@ contract L2CompressorHuffReadFlagTests is AdvTest { ); } - function test_read_flag_bytes32_zero(bytes32 _data) external { - (bool s, bytes memory r) = imp.staticcall( - abi.encodePacked(hex"00", _data) - ); - - assertTrue(s); - (uint256 rindex, uint256 windex, bytes memory res) = abi.decode(r, (uint256, uint256, bytes)); - assertEq(rindex, 1); - assertEq(windex, FMS + 32); - - assertEq(abi.encode(uint256(0)), res); - } - function test_read_flag_bytes32_one(uint8 _val) external { (bool s, bytes memory r) = imp.staticcall( abi.encodePacked(hex"01", _val) @@ -65,7 +52,7 @@ contract L2CompressorHuffReadFlagTests is AdvTest { } function test_read_flag_bytes32_x(uint256 _size, bytes memory _content) public { - _size = bound(_size, 0, 32); + _size = bound(_size, 1, 32); (bool s, bytes memory r) = imp.staticcall( abi.encodePacked(uint8(_size), _content) @@ -994,4 +981,38 @@ contract L2CompressorHuffReadFlagTests is AdvTest { assertEq(rindex, encoded.length); assertEq(res, abi.encode(_val)); } + + function test_read_pow_10(uint256 _exp) external { + _exp = bound(_exp, 0, 77); + + // First bit means we aren't going to multiply it after + bytes memory encoded = abi.encodePacked(uint8(0x00), uint8(_exp) | uint8(0x80)); + + (bool s, bytes memory r) = imp.call(encoded); + assertTrue(s); + + (uint256 rindex, uint256 windex, bytes memory res) = abi.decode(r, (uint256, uint256, bytes)); + + assertEq(windex, FMS + res.length); + assertEq(rindex, encoded.length); + assertEq(res, abi.encode(uint256(10 ** _exp))); + } + + function test_read_pow_10_and_mul(uint256 _exp, uint8 _factor) external { + _exp = bound(_exp, 0, 77); + + // First bit means we aren't going to multiply it after + bytes memory encoded = abi.encodePacked(uint8(0x00), uint8(_exp), uint8(_factor)); + + (bool s, bytes memory r) = imp.call(encoded); + assertTrue(s); + + (uint256 rindex, uint256 windex, bytes memory res) = abi.decode(r, (uint256, uint256, bytes)); + + unchecked { + assertEq(windex, FMS + res.length); + assertEq(rindex, encoded.length); + assertEq(res, abi.encode(uint256(10 ** _exp) * uint256(_factor))); + } + } } diff --git a/src/L2Compressor.huff b/src/L2Compressor.huff index 079480c..82cba5d 100644 --- a/src/L2Compressor.huff +++ b/src/L2Compressor.huff @@ -87,7 +87,7 @@ } #define jumptable__packed FLAG_TABLE { - FLAG_READ_BYTES32_0_BYTES // 0x00 + FLAG_READ_POWER_OF_10 // 0x00 FLAG_READ_BYTES32_1_BYTES // 0x01 FLAG_READ_BYTES32_2_BYTES // 0x02 FLAG_READ_BYTES32_3_BYTES // 0x03 @@ -217,8 +217,8 @@ 0xf0 shr // [word >> 0xf0, windex, rindex + 1, jump_to] jump // [windex, rindex + 1, jump_to] - FLAG_READ_BYTES32_0_BYTES: - READ_BYTES32_EMPTY() + FLAG_READ_POWER_OF_10: + READ_POW_10() end jump FLAG_READ_BYTES32_1_BYTES: READ_BYTES32(0xf8, 0x01) @@ -490,6 +490,64 @@ // output stack: // [windex, rindex] } +#define macro READ_POW_10() = takes (2) returns (2) { + // input stack: [windex, rindex] + + swap1 // [rindex, windex] + LOAD_DYNAMIC_SIZE(0x01, 0xf8) // [exp_word, rindex, windex] + + // The last bit determines if we will multiply this by + // the next byte or not, this is fine as the maximum value that we + // can represent in a word is only 10 ** 78 + dup1 // [exp_word, exp_word, rindex, windex] + 0x80 and // [not_use_mul, exp_word, rindex, windex] + swap1 // [exp_word, not_use_mul, rindex, windex] + 0x7f and // [exp, not_use_mul, rindex, windex] + + swap3 // [windex, not_use_mul, rindex, exp_word] + swap1 // [not_use_mul, windex, rindex, exp_word] + swap3 // [exp_word, windex, rindex, not_use_mul] + + POW_10() // [windex, rindex, not_use_mul] + swap1 // [rindex, windex, not_use_mul] + swap2 // [not_use_mul, windex, rindex] + + no_mul jumpi // [windex, rindex] + BACKREAD_SINGLE_VALUE() // [pow_result, windex, rindex] + swap2 // [rindex, windex, pow_result] + LOAD_DYNAMIC_SIZE(0x01, 0xf8) // [factor, rindex, windex, pow_result] + swap1 // [rindex, factor, windex, pow_result] + swap3 // [pow_result, factor, windex, rindex] + mul // [(pow_result * factor), windex, rindex] + dup2 // [windex, (pow_result * factor), windex, rindex] + mstore // [windex, rindex] + 0x20 // [0x20, windex, rindex] + add // [(0x20 + windex), rindex] + + no_mul: // [windex, rindex] + + // output stack: [windex, rindex] +} + +#define macro POW_10() = takes (2) returns (1) { + // input stack: [exp, windex] + + 0x05 // [0x05, exp, windex] + shl // [exp * 0x20, windex] + + __tablestart(POW_10_TABLE) // [table_start, exp * 0x20, windex] + add // [(table_start + exp * 0x20), windex] + + 0x20 // [0x20, (table_start + exp * 0x20), windex] + swap1 // [(table_start + exp * 0x20), 0x20, windex] + dup3 // [windex, (table_start + exp * 0x20), 0x20, windex] + codecopy // [windex] + + 0x20 add // [windex + 0x20] + + // output stack: [windex] +} + #define macro READ_MIRROR_FLAG(nrfs) = takes (2) returns (2) { // input stack: [windex, rindex] @@ -1095,22 +1153,6 @@ [FMS] mload 0xf1f2 eq ASSERT() // [] } -#[calldata("0x1000")] -#define test TEST_READ_FLAG_0_BYTES() = { - 0x02 // [rindex] - [FMS] // [windex, rindex] - - // Store something - 0x10 [FMS] mstore - - READ_FLAG() // [windex, rindex] - - 0x20 [FMS] add eq ASSERT() // [rindex] - 0x03 eq ASSERT() // [] - - [FMS] mload 0x00 eq ASSERT() // [] -} - #define test TEST_NUMS() = { ADDRESSES_NUM() // [num] 0x00 eq ASSERT() // [] @@ -1825,19 +1867,6 @@ // output stack: [0x20 + windex, valB + rindex] } -#define macro READ_BYTES32_EMPTY() = takes (3) returns (2) { - // input stack: [windex, rindex] - - callvalue // [0x00, windex, rindex] - dup2 // [windex, 0x00, windex, rindex] - mstore // [windex, rindex] - - 0x20 // [0x20, windex, rindex] - add // [(0x20 + windex), rindex] - - // input stack: [windex, rindex] -} - #define macro READ_BYTES32_WORD() = takes (3) returns (2) { // input stack: [windex, rindex] @@ -1891,16 +1920,6 @@ [FMS] 0x40 add mload 0xb2d10eb37ef5838bb835ea71bbd4053daf8de7bd8ecdf638451a2bc966a145a8 eq ASSERT() // [] - - 0x15 // [rindex] - [FMS] 0x10 add // [windex, rindex] - - READ_BYTES32_EMPTY() // [windex, rindex] - - [FMS] 0x30 add eq ASSERT() // [rindex] - 0x15 eq ASSERT() // [] - - [FMS] 0x10 add mload 0x00 eq ASSERT() // [] } #define macro SAVE_ADDRESS() = takes (3) returns (2) { @@ -2274,3 +2293,7 @@ 0x7ef5838bb8 eq ASSERT() // [rindex] 0x09 eq ASSERT() // [] } + +#define table POW_10_TABLE { + 0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000003e8000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000000f424000000000000000000000000000000000000000000000000000000000009896800000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000002540be400000000000000000000000000000000000000000000000000000000174876e800000000000000000000000000000000000000000000000000000000e8d4a51000000000000000000000000000000000000000000000000000000009184e72a00000000000000000000000000000000000000000000000000000005af3107a400000000000000000000000000000000000000000000000000000038d7ea4c68000000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000000000000000000000000000016345785d8a00000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000008ac7230489e800000000000000000000000000000000000000000000000000056bc75e2d6310000000000000000000000000000000000000000000000000003635c9adc5dea0000000000000000000000000000000000000000000000000021e19e0c9bab240000000000000000000000000000000000000000000000000152d02c7e14af680000000000000000000000000000000000000000000000000d3c21bcecceda1000000000000000000000000000000000000000000000000084595161401484a00000000000000000000000000000000000000000000000052b7d2dcc80cd2e40000000000000000000000000000000000000000000000033b2e3c9fd0803ce80000000000000000000000000000000000000000000000204fce5e3e250261100000000000000000000000000000000000000000000001431e0fae6d7217caa0000000000000000000000000000000000000000000000c9f2c9cd04674edea40000000000000000000000000000000000000000000007e37be2022c0914b268000000000000000000000000000000000000000000004ee2d6d415b85acef8100000000000000000000000000000000000000000000314dc6448d9338c15b0a00000000000000000000000000000000000000000001ed09bead87c0378d8e6400000000000000000000000000000000000000000013426172c74d822b878fe8000000000000000000000000000000000000000000c097ce7bc90715b34b9f1000000000000000000000000000000000000000000785ee10d5da46d900f436a000000000000000000000000000000000000000004b3b4ca85a86c47a098a22400000000000000000000000000000000000000002f050fe938943acc45f655680000000000000000000000000000000000000001d6329f1c35ca4bfabb9f561000000000000000000000000000000000000000125dfa371a19e6f7cb54395ca000000000000000000000000000000000000000b7abc627050305adf14a3d9e40000000000000000000000000000000000000072cb5bd86321e38cb6ce6682e8000000000000000000000000000000000000047bf19673df52e37f2410011d100000000000000000000000000000000000002cd76fe086b93ce2f768a00b22a0000000000000000000000000000000000001c06a5ec5433c60ddaa16406f5a400000000000000000000000000000000000118427b3b4a05bc8a8a4de845986800000000000000000000000000000000000af298d050e4395d69670b12b7f41000000000000000000000000000000000006d79f82328ea3da61e066ebb2f88a0000000000000000000000000000000000446c3b15f9926687d2c40534fdb5640000000000000000000000000000000002ac3a4edbbfb8014e3ba83411e915e8000000000000000000000000000000001aba4714957d300d0e549208b31adb10000000000000000000000000000000010b46c6cdd6e3e0828f4db456ff0c8ea00000000000000000000000000000000a70c3c40a64e6c51999090b65f67d92400000000000000000000000000000006867a5a867f103b2fffa5a71fba0e7b680000000000000000000000000000004140c78940f6a24fdffc78873d4490d2100000000000000000000000000000028c87cb5c89a2571ebfdcb54864ada834a00000000000000000000000000000197d4df19d605767337e9f14d3eec8920e400000000000000000000000000000fee50b7025c36a0802f236d04753d5b48e800000000000000000000000000009f4f2726179a224501d762422c946590d91000000000000000000000000000063917877cec0556b21269d695bdcbf7a87aa0000000000000000000000000003e3aeb4ae1383562f4b82261d969f7ac94ca40000000000000000000000000026e4d30eccc3215dd8f3157d27e23acbdcfe680000000000000000000000000184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000000000000000f316271c7fc3908a8bef464e3945ef7a25360a000000000000000000000000097edd871cfda3a5697758bf0e3cbb5ac5741c640000000000000000000000005ef4a74721e864761ea977768e5f518bb6891be8000000000000000000000003b58e88c75313ec9d329eaaa18fb92f75215b1710000000000000000000000025179157c93ec73e23fa32aa4f9d3bda934d8ee6a0000000000000000000000172ebad6ddc73c86d67c5faa71c245689c107950240000000000000000000000e7d34c64a9c85d4460dbbca87196b61618a4bd216800000000000000000000090e40fbeea1d3a4abc8955e946fe31cdcf66f634e10000000000000000000005a8e89d75252446eb5d5d5b1cc5edf20a1a059e10ca000000000000000000003899162693736ac531a5a58f1fbb4b746504382ca7e40000000000000000000235fadd81c2822bb3f07877973d50f28bf22a31be8ee8000000000000000000161bcca7119915b50764b4abe86529797775a5f1719510000000000000000000dd15fe86affad91249ef0eb713f39ebeaa987b6e6fd2a0000000000000000000 +}