|
| 1 | +/// Returns the length of the data after compression through FastLZ, based on |
| 2 | +// https://github.com/Vectorized/solady/blob/5315d937d79b335c668896d7533ac603adac5315/js/solady.js |
| 3 | +pub(crate) fn flz_compress_len(input: &[u8]) -> u32 { |
| 4 | + let mut idx: u32 = 2; |
| 5 | + |
| 6 | + let idx_limit: u32 = if input.len() < 13 { |
| 7 | + 0 |
| 8 | + } else { |
| 9 | + input.len() as u32 - 13 |
| 10 | + }; |
| 11 | + |
| 12 | + let mut anchor = 0; |
| 13 | + |
| 14 | + let mut size = 0; |
| 15 | + |
| 16 | + let mut htab = [0; 8192]; |
| 17 | + |
| 18 | + while idx < idx_limit { |
| 19 | + let mut r: u32; |
| 20 | + let mut distance: u32; |
| 21 | + |
| 22 | + loop { |
| 23 | + let seq = u24(input, idx); |
| 24 | + let hash = hash(seq); |
| 25 | + r = htab[hash as usize]; |
| 26 | + htab[hash as usize] = idx; |
| 27 | + distance = idx - r; |
| 28 | + if idx >= idx_limit { |
| 29 | + break; |
| 30 | + } |
| 31 | + idx += 1; |
| 32 | + if distance < 8192 && seq == u24(input, r) { |
| 33 | + break; |
| 34 | + } |
| 35 | + } |
| 36 | + |
| 37 | + if idx >= idx_limit { |
| 38 | + break; |
| 39 | + } |
| 40 | + |
| 41 | + idx -= 1; |
| 42 | + |
| 43 | + if idx > anchor { |
| 44 | + size = literals(idx - anchor, size); |
| 45 | + } |
| 46 | + |
| 47 | + let len = cmp(input, r + 3, idx + 3, idx_limit + 9); |
| 48 | + size = flz_match(len, size); |
| 49 | + |
| 50 | + idx = set_next_hash(&mut htab, input, idx + len); |
| 51 | + idx = set_next_hash(&mut htab, input, idx); |
| 52 | + anchor = idx; |
| 53 | + } |
| 54 | + |
| 55 | + literals(input.len() as u32 - anchor, size) |
| 56 | +} |
| 57 | + |
| 58 | +fn literals(r: u32, size: u32) -> u32 { |
| 59 | + let size = size + 0x21 * (r / 0x20); |
| 60 | + let r = r % 0x20; |
| 61 | + if r != 0 { |
| 62 | + size + r + 1 |
| 63 | + } else { |
| 64 | + size |
| 65 | + } |
| 66 | +} |
| 67 | + |
| 68 | +fn cmp(input: &[u8], p: u32, q: u32, r: u32) -> u32 { |
| 69 | + let mut l = 0; |
| 70 | + let mut r = r - q; |
| 71 | + while l < r { |
| 72 | + if input[(p + l) as usize] != input[(q + l) as usize] { |
| 73 | + r = 0; |
| 74 | + } |
| 75 | + l += 1; |
| 76 | + } |
| 77 | + l |
| 78 | +} |
| 79 | + |
| 80 | +fn flz_match(l: u32, size: u32) -> u32 { |
| 81 | + let l = l - 1; |
| 82 | + let size = size + (3 * (l / 262)); |
| 83 | + if l % 262 >= 6 { |
| 84 | + size + 3 |
| 85 | + } else { |
| 86 | + size + 2 |
| 87 | + } |
| 88 | +} |
| 89 | + |
| 90 | +fn set_next_hash(htab: &mut [u32; 8192], input: &[u8], idx: u32) -> u32 { |
| 91 | + htab[hash(u24(input, idx)) as usize] = idx; |
| 92 | + idx + 1 |
| 93 | +} |
| 94 | + |
| 95 | +fn hash(v: u32) -> u16 { |
| 96 | + let hash = (v as u64 * 2654435769) >> 19; |
| 97 | + hash as u16 & 0x1fff |
| 98 | +} |
| 99 | + |
| 100 | +fn u24(input: &[u8], idx: u32) -> u32 { |
| 101 | + u32::from(input[idx as usize]) |
| 102 | + + (u32::from(input[(idx + 1) as usize]) << 8) |
| 103 | + + (u32::from(input[(idx + 2) as usize]) << 16) |
| 104 | +} |
| 105 | + |
| 106 | +#[cfg(test)] |
| 107 | +mod tests { |
| 108 | + use alloy_sol_types::sol; |
| 109 | + use alloy_sol_types::SolCall; |
| 110 | + |
| 111 | + use super::*; |
| 112 | + use crate::db::BenchmarkDB; |
| 113 | + use crate::{ |
| 114 | + primitives::address, primitives::bytes, primitives::Bytecode, primitives::Bytes, |
| 115 | + primitives::TransactTo, primitives::U256, Evm, |
| 116 | + }; |
| 117 | + |
| 118 | + use rstest::rstest; |
| 119 | + |
| 120 | + #[rstest] |
| 121 | + #[case::empty(&[], 0)] |
| 122 | + #[case::thousand_zeros(&[0; 1000], 21)] |
| 123 | + #[case::thousand_fourty_twos(&[42; 1000], 21)] |
| 124 | + #[case::short_hex(&bytes!("FACADE"), 4)] |
| 125 | + #[case::sample_contract_call(&bytes!("02f901550a758302df1483be21b88304743f94f80e51afb613d764fa61751affd3313c190a86bb870151bd62fd12adb8e41ef24f3f000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e5831000000000000000000000000000000000000000000000000000000000003c1e5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000148c89ed219d02f1a5be012c689b4f5b731827bebe000000000000000000000000c001a033fd89cb37c31b2cba46b6466e040c61fc9b2a3675a7f5f493ebd5ad77c497f8a07cdf65680e238392693019b4092f610222e71b7cec06449cb922b93b6a12744e"), 202)] |
| 126 | + #[case::base_0x5dadeb52979f29fc7a7494c43fdabc5be1d8ff404f3aafe93d729fa8e5d00769(&bytes!("b9047c02f904788221050883036ee48409c6c87383037f6f941195cf65f83b3a5768f3c496d3a05ad6412c64b78644364c5bb000b90404d123b4d80000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000f6476f90447748c19248ccaa31e6b8bfda4eb9d830f5f47df7f0998f7c2123d9e6137761b75d3184efb0f788e3b14516000000000000000000000000000000000000000000000000000044364c5bb000000000000000000000000000f38e53bd45c8225a7c94b513beadaa7afe5d222d0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084d6574614d61736b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d656852577a743347745961776343347564745657557233454c587261436746434259416b66507331696f48610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd0d83d9e840f8e27d5c2e365fd365ff1c05b2480000000000000000000000000000000000000000000000000000000000000ce40000000000000000000000000000000000000000000000000000000000000041e4480d358dbae20880960a0a464d63b06565a0c9f9b1b37aa94b522247b23ce149c81359bf4239d1a879eeb41047ec710c15f5c0f67453da59a383e6abd742971c00000000000000000000000000000000000000000000000000000000000000c001a0b57f0ff8516ea29cb26a44ac5055a5420847d1e16a8e7b03b70f0c02291ff2d5a00ad3771e5f39ccacfff0faa8c5d25ef7a1c179f79e66e828ffddcb994c8b512e"), 471)] |
| 127 | + fn test_flz_compress_len(#[case] input: &[u8], #[case] expected: u32) { |
| 128 | + assert_eq!(flz_compress_len(input), expected); |
| 129 | + } |
| 130 | + |
| 131 | + #[test] |
| 132 | + fn test_flz_compress_len_no_repeats() { |
| 133 | + let mut input = Vec::new(); |
| 134 | + let mut len = 0; |
| 135 | + |
| 136 | + for i in 0..256 { |
| 137 | + input.push(i as u8); |
| 138 | + let prev_len = len; |
| 139 | + len = flz_compress_len(&input); |
| 140 | + assert!(len > prev_len); |
| 141 | + } |
| 142 | + } |
| 143 | + |
| 144 | + #[rstest] |
| 145 | + #[case::short_hex(bytes!("FACADE"))] |
| 146 | + #[case::sample_contract_call(bytes!("02f901550a758302df1483be21b88304743f94f80e51afb613d764fa61751affd3313c190a86bb870151bd62fd12adb8e41ef24f3f000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e5831000000000000000000000000000000000000000000000000000000000003c1e5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000148c89ed219d02f1a5be012c689b4f5b731827bebe000000000000000000000000c001a033fd89cb37c31b2cba46b6466e040c61fc9b2a3675a7f5f493ebd5ad77c497f8a07cdf65680e238392693019b4092f610222e71b7cec06449cb922b93b6a12744e"))] |
| 147 | + #[case::base_0x5dadeb52979f29fc7a7494c43fdabc5be1d8ff404f3aafe93d729fa8e5d00769(bytes!("b9047c02f904788221050883036ee48409c6c87383037f6f941195cf65f83b3a5768f3c496d3a05ad6412c64b78644364c5bb000b90404d123b4d80000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000f6476f90447748c19248ccaa31e6b8bfda4eb9d830f5f47df7f0998f7c2123d9e6137761b75d3184efb0f788e3b14516000000000000000000000000000000000000000000000000000044364c5bb000000000000000000000000000f38e53bd45c8225a7c94b513beadaa7afe5d222d0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084d6574614d61736b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d656852577a743347745961776343347564745657557233454c587261436746434259416b66507331696f48610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd0d83d9e840f8e27d5c2e365fd365ff1c05b2480000000000000000000000000000000000000000000000000000000000000ce40000000000000000000000000000000000000000000000000000000000000041e4480d358dbae20880960a0a464d63b06565a0c9f9b1b37aa94b522247b23ce149c81359bf4239d1a879eeb41047ec710c15f5c0f67453da59a383e6abd742971c00000000000000000000000000000000000000000000000000000000000000c001a0b57f0ff8516ea29cb26a44ac5055a5420847d1e16a8e7b03b70f0c02291ff2d5a00ad3771e5f39ccacfff0faa8c5d25ef7a1c179f79e66e828ffddcb994c8b512e"))] |
| 148 | + #[case::base_0xfaada76a2dac09fc17f5a28d066aaabefc6d82ef6589b211ed8c9f766b070721(bytes!("b87602f873822105528304320f8409cfe5c98252089480c67432656d59144ceff962e8faf8926599bcf888011dfe52d06b633f80c001a08632f069f837aea7a28bab0affee14dda116956bd5a850a355c045d25afedd17a0084b8f273efffe17ece527116053e5781a4915ff89ab9c379f1e62c25b697687"))] |
| 149 | + #[case::base_0x112864e9b971af6a1dac840018833c5a5a659acc187cfdaba919ad1da013678d(bytes!("b8b302f8b0822105308304320f8409cfe5c9827496944ed4e862860bed51a9570b96d89af5e1b0efefed80b844095ea7b3000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba300000000000000000000000000000000000000000000015e10fb0973595fffffc001a02020e39f07917c1a852feb131c857e12478c7e88a20772b91a8bf5cee38c5aeea06055981727f9aaa3471c1af800555b35a77916c154be3f9d02ad1a63029455ab"))] |
| 150 | + #[case::base_0x6905051352691641888d0c427fb137c5b95afb5870d5169ff014eff1d0952195(bytes!("b87202f86f8221058303dc6c8310db1f84068fa8d7838954409436af2ff952a7355c8045fcd5e88bc9f6c8257f7b8080c001a0b89e7ff3d7694109e73e7f4244e032581670313c36e48e485c9c94b853bd81d2a038ffaf8f10859ce21d1f7f7046c3d08027fb8aa15b69038f6102be97aaa1179a"))] |
| 151 | + #[case::base_0x6a38e9a26d7202a2268de69d2d47531c1a9829867579a483fb48d78e9e0b080d(bytes!("b9049b02f904978221058201618506fc23ac008506fc23ac008306ddd0943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad80b904243593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000006641d67b00000000000000000000000000000000000000000000000000000000000000030a000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000088487bd8c3222d64d1d0b3fa7098dcf9d94d79e000000000000000000000000ffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000006669635d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad000000000000000000000000000000000000000000000000000000006641d78900000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000418661369ca026f92ff88347bd0e3625a7b5ed65071b366368c68ad7c55aed136c18659b34f9246e30a784227a53dd374fbd3d2124696808c678cd987c4e954a681b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000549e5c020c764dbfffff00000000000000000000000000000000000000000000000002e5a629c093a2b600000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002b088487bd8c3222d64d1d0b3fa7098dcf9d94d79e0027104200000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000c001a014a3acef764ff6d3bb9bd81e420bfa94171a5734ab997dfbc9b41b653ce018a4a01ff5fccb01ef5c60ba3aef67d4e74f3f47312dd78bfbbff9e5090fbf2d3d62bb"))] |
| 152 | + fn test_flz_native_evm_parity(#[case] input: Bytes) { |
| 153 | + // This bytecode and ABI is for a contract, which wraps the LibZip library for easier fuzz testing. |
| 154 | + // The source of this contract is here: https://github.com/danyalprout/fastlz/blob/main/src/FastLz.sol#L6-L10 |
| 155 | + sol! { |
| 156 | + interface FastLz { |
| 157 | + function fastLz(bytes input) external view returns (uint256); |
| 158 | + } |
| 159 | + } |
| 160 | + |
| 161 | + let contract_bytecode = Bytecode::new_raw(bytes!("608060405234801561001057600080fd5b506004361061002b5760003560e01c8063920a769114610030575b600080fd5b61004361003e366004610374565b610055565b60405190815260200160405180910390f35b600061006082610067565b5192915050565b60606101e0565b818153600101919050565b600082840393505b838110156100a25782810151828201511860001a1590930292600101610081565b9392505050565b825b602082106100d75782516100c0601f8361006e565b5260209290920191601f19909101906021016100ab565b81156100a25782516100ec600184038361006e565b520160010192915050565b60006001830392505b61010782106101385761012a8360ff1661012560fd6101258760081c60e0018961006e565b61006e565b935061010682039150610100565b600782106101655761015e8360ff16610125600785036101258760081c60e0018961006e565b90506100a2565b61017e8360ff166101258560081c8560051b018761006e565b949350505050565b80516101d890838303906101bc90600081901a600182901a60081b1760029190911a60101b17639e3779b90260131c611fff1690565b8060021b6040510182815160e01c1860e01b8151188152505050565b600101919050565b5060405161800038823961800081016020830180600d8551820103826002015b81811015610313576000805b50508051604051600082901a600183901a60081b1760029290921a60101b91909117639e3779b9810260111c617ffc16909101805160e081811c878603811890911b9091189091528401908183039084841061026857506102a3565b600184019350611fff821161029d578251600081901a600182901a60081b1760029190911a60101b17810361029d57506102a3565b5061020c565b8383106102b1575050610313565b600183039250858311156102cf576102cc87878886036100a9565b96505b6102e3600985016003850160038501610079565b91506102f08782846100f7565b9650506103088461030386848601610186565b610186565b915050809350610200565b5050617fe061032884848589518601036100a9565b03925050506020820180820383525b81811161034e57617fe08101518152602001610337565b5060008152602001604052919050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561038657600080fd5b813567ffffffffffffffff8082111561039e57600080fd5b818401915084601f8301126103b257600080fd5b8135818111156103c4576103c461035e565b604051601f8201601f19908116603f011681019083821181831017156103ec576103ec61035e565b8160405282815287602084870101111561040557600080fd5b82602086016020830137600092810160200192909252509594505050505056fea264697066735822122000646b2953fc4a6f501bd0456ac52203089443937719e16b3190b7979c39511264736f6c63430008190033")); |
| 162 | + |
| 163 | + let native_val = flz_compress_len(&input); |
| 164 | + |
| 165 | + let mut evm = Evm::builder() |
| 166 | + .with_db(BenchmarkDB::new_bytecode(contract_bytecode.clone())) |
| 167 | + .modify_tx_env(|tx| { |
| 168 | + tx.caller = address!("1000000000000000000000000000000000000000"); |
| 169 | + tx.transact_to = |
| 170 | + TransactTo::Call(address!("0000000000000000000000000000000000000000")); |
| 171 | + tx.data = FastLz::fastLzCall::new((input,)).abi_encode().into(); |
| 172 | + }) |
| 173 | + .build(); |
| 174 | + |
| 175 | + let result_and_state = evm.transact().unwrap(); |
| 176 | + let output = result_and_state.result.output().unwrap(); |
| 177 | + let evm_val = FastLz::fastLzCall::abi_decode_returns(output, true) |
| 178 | + .unwrap() |
| 179 | + ._0; |
| 180 | + |
| 181 | + assert_eq!(U256::from(native_val), evm_val); |
| 182 | + } |
| 183 | +} |
0 commit comments