@@ -38,6 +38,29 @@ contract LibZipTest is SoladyTest {
3838 bytes internal constant _CD_COMPRESS_INPUT =
3939 hex "00000000000000000000000000000000000000000000000000000000000ae11c0000000000000000000000000000000000000000000000000000002b9cdca0ab0000000000000000000000000000000000003961790f8baa365051889e4c367d00000000000000000000000000000000000026d85539440bc844167ac0cc42320000000000000000000000000000000000000000000000007b55939986433925 " ;
4040
41+ bytes internal constant _CD_COMPRESS_OUTPUT =
42+ hex "ffe3f51e1c001a2b9cdca0ab00113961790f8baa365051889e4c367d001126d85539440bc844167ac0cc423200177b55939986433925 " ;
43+
44+ function testABCCdCompressAndDecompressGas () public {
45+ bytes memory data = abi.encode (_A, _B, _C);
46+ assertEq (LibZip.cdDecompress (LibZip.cdCompress (data)).length , data.length );
47+ }
48+
49+ function testABCCdCompressAndDecompressOriginalGas () public {
50+ bytes memory data = abi.encode (_A, _B, _C);
51+ assertEq (_cdDecompressOriginal (_cdCompressOriginal (data)).length , data.length );
52+ }
53+
54+ function testCdDecompressGas () public {
55+ bytes memory data = _CD_COMPRESS_OUTPUT;
56+ assertGt (LibZip.cdDecompress (data).length , data.length );
57+ }
58+
59+ function testCdDecompressOriginalGas () public {
60+ bytes memory data = _CD_COMPRESS_OUTPUT;
61+ assertGt (_cdDecompressOriginal (data).length , data.length );
62+ }
63+
4164 function testCdCompressGas () public {
4265 bytes memory data = _CD_COMPRESS_INPUT;
4366 assertLt (LibZip.cdCompress (data).length , data.length );
@@ -48,15 +71,15 @@ contract LibZipTest is SoladyTest {
4871 assertLt (_cdCompressOriginal (data).length , data.length );
4972 }
5073
51- function testStoreABCWithCdCompressGas () public {
74+ function testABCStoreWithCdCompressGas () public {
5275 _bytesStorage.set (LibZip.cdCompress (abi.encode (_A, _B, _C)));
5376 }
5477
55- function testStoreABCWithCdCompressOriginalGas () public {
78+ function testABCStoreWithCdCompressOriginalGas () public {
5679 _bytesStorage.set (_cdCompressOriginal (abi.encode (_A, _B, _C)));
5780 }
5881
59- function testStoreABCWithFlzCompressGas () public {
82+ function testABCStoreWithFlzCompressGas () public {
6083 _bytesStorage.set (LibZip.flzCompress (abi.encode (_A, _B, _C)));
6184 }
6285
@@ -73,11 +96,36 @@ contract LibZipTest is SoladyTest {
7396 }
7497
7598 function testCdCompressDifferential (bytes32 ) public {
76- testCdCompressDifferential (_randomCd ());
99+ bytes memory data;
100+ if (_randomChance (8 )) data = _randomCd ();
101+ uint256 t = _randomUniform () % 4 ;
102+ for (uint256 i; i < t; ++ i) {
103+ if (_randomChance (2 )) data = abi.encodePacked (data, _random ());
104+ if (_randomChance (2 )) data = abi.encodePacked (data, new bytes (_random () & 0x3ff ));
105+ if (_randomChance (2 )) data = abi.encodePacked (data, _random ());
106+ if (_randomChance (32 )) data = abi.encodePacked (data, _randomCd ());
107+ }
108+ testCdCompressDifferential (data);
77109 }
78110
79111 function testCdCompressDifferential (bytes memory data ) public {
80- assertEq (LibZip.cdCompress (data), _cdCompressOriginal (data));
112+ if (_randomChance (32 )) _misalignFreeMemoryPointer ();
113+ if (_randomChance (32 )) _brutalizeMemory ();
114+ bytes memory computed = LibZip.cdCompress (data);
115+ assertEq (computed, _cdCompressOriginal (data));
116+ }
117+
118+ function testCdDecompressDifferential (bytes32 ) public {
119+ bytes memory data = _randomCd ();
120+ if (_randomChance (2 )) {
121+ testCdDecompressDifferential (LibZip.cdCompress (data));
122+ } else {
123+ testCdDecompressDifferential (data);
124+ }
125+ }
126+
127+ function testCdDecompressDifferential (bytes memory data ) public {
128+ assertEq (LibZip.cdDecompress (data), _cdDecompressOriginal (data));
81129 }
82130
83131 function _cdCompressOriginal (bytes memory data ) internal pure returns (bytes memory result ) {
@@ -121,6 +169,39 @@ contract LibZipTest is SoladyTest {
121169 }
122170 }
123171
172+ function _cdDecompressOriginal (bytes memory data ) internal pure returns (bytes memory result ) {
173+ /// @solidity memory-safe-assembly
174+ assembly {
175+ if mload (data) {
176+ result := mload (0x40 )
177+ let o := add (result, 0x20 )
178+ let s := add (data, 4 )
179+ let v := mload (s)
180+ let end := add (data, mload (data))
181+ mstore (s, not (v)) // Bitwise negate the first 4 bytes.
182+ for {} lt (data, end) {} {
183+ data := add (data, 1 )
184+ let c := byte (31 , mload (data))
185+ if iszero (c) {
186+ data := add (data, 1 )
187+ let d := byte (31 , mload (data))
188+ // Fill with either 0xff or 0x00.
189+ mstore (o, not (0 ))
190+ if iszero (gt (d, 0x7f )) { calldatacopy (o, calldatasize (), add (d, 1 )) }
191+ o := add (o, add (and (d, 0x7f ), 1 ))
192+ continue
193+ }
194+ mstore8 (o, c)
195+ o := add (o, 1 )
196+ }
197+ mstore (s, v) // Restore the first 4 bytes.
198+ mstore (result, sub (o, add (result, 0x20 ))) // Store the length.
199+ mstore (o, 0 ) // Zeroize the slot after the string.
200+ mstore (0x40 , add (o, 0x20 )) // Allocate the memory.
201+ }
202+ }
203+ }
204+
124205 function testFlzCompressDecompress () public brutalizeMemory {
125206 assertEq (LibZip.flzCompress ("" ), "" );
126207 assertEq (LibZip.flzDecompress ("" ), "" );
@@ -211,7 +292,18 @@ contract LibZipTest is SoladyTest {
211292 function _randomCd () internal returns (bytes memory data ) {
212293 uint256 n = _randomChance (8 ) ? _random () % 2048 : _random () % 256 ;
213294 data = new bytes (n);
214- if (_randomChance (2 )) {
295+ if (_randomChance (32 )) {
296+ uint256 r = _randomUniform ();
297+ /// @solidity memory-safe-assembly
298+ assembly {
299+ mstore (0x00 , r)
300+ for { let i := 0 } lt (i, n) { i := add (i, 0x20 ) } {
301+ mstore (0x20 , xor ("randomUniform " , i))
302+ mstore (add (add (data, 0x20 ), i), keccak256 (0x00 , 0x40 ))
303+ }
304+ }
305+ }
306+ if (_randomChance (4 )) {
215307 /// @solidity memory-safe-assembly
216308 assembly {
217309 for { let i := 0 } lt (i, n) { i := add (i, 0x20 ) } {
@@ -224,16 +316,45 @@ contract LibZipTest is SoladyTest {
224316 /// @solidity memory-safe-assembly
225317 assembly {
226318 mstore (0x00 , r)
319+ mstore (0x20 , xor ("mode " , not (0 )))
320+ let mode := and (1 , keccak256 (0x00 , 0x40 ))
227321 for { let i := 0 } lt (i, n) { i := add (i, 0x20 ) } {
228- mstore (0x20 , i)
229- if and (1 , keccak256 (0x00 , 0x40 )) { mstore (add (add (data, 0x20 ), i), 0 ) }
322+ mstore (0x20 , xor ("mode " , i))
323+ mode := xor (mode, iszero (and (keccak256 (0x00 , 0x40 ), 7 )))
324+ mstore (add (add (data, 0x20 ), i), mul (iszero (mode), not (0 )))
230325 }
231326 }
232327 }
233- if (n != 0 ) {
234- uint256 m = _random () % 8 ;
235- for (uint256 j; j < m; ++ j) {
236- data[_random () % n] = bytes1 (uint8 (_random ()));
328+ if (_randomChance (16 )) {
329+ uint256 r = _randomUniform ();
330+ /// @solidity memory-safe-assembly
331+ assembly {
332+ mstore (0x00 , r)
333+ for { let i := 0 } lt (i, n) { i := add (i, 0x20 ) } {
334+ mstore (0x20 , xor ("0 " , i))
335+ let p := keccak256 (0x00 , 0x40 )
336+ if and (0x01 , p) { mstore (add (add (data, 0x20 ), i), 0 ) }
337+ }
338+ }
339+ }
340+ if (_randomChance (16 )) {
341+ uint256 r = _randomUniform ();
342+ /// @solidity memory-safe-assembly
343+ assembly {
344+ mstore (0x00 , r)
345+ for { let i := 0 } lt (i, n) { i := add (i, 0x20 ) } {
346+ mstore (0x20 , xor ("not(0) " , i))
347+ let p := keccak256 (0x00 , 0x40 )
348+ if and (0x10 , p) { mstore (add (add (data, 0x20 ), i), not (0 )) }
349+ }
350+ }
351+ }
352+ if (_randomChance (2 )) {
353+ if (n != 0 ) {
354+ uint256 m = _random () % 8 ;
355+ for (uint256 j; j < m; ++ j) {
356+ data[_random () % n] = bytes1 (uint8 (_random ()));
357+ }
237358 }
238359 }
239360 }
@@ -393,4 +514,27 @@ contract LibZipTest is SoladyTest {
393514 }
394515 assertEq (a, b);
395516 }
517+
518+ function testCountLeadingNonZeroBytes (bytes32 s ) public {
519+ uint256 expected;
520+ uint256 computed;
521+ /// @solidity memory-safe-assembly
522+ assembly {
523+ let n := 0
524+ for {} byte (n, s) { n := add (n, 1 ) } {} // Scan for '\0'.
525+ expected := n
526+ let m := 0x7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F
527+ let x := not (or (or (add (and (s, m), m), s), m))
528+ computed := 0x20
529+ if x {
530+ let r := shl (7 , lt (0xffffffffffffffffffffffffffffffff , x))
531+ r := or (r, shl (6 , lt (0xffffffffffffffff , shr (r, x))))
532+ r := or (r, shl (5 , lt (0xffffffff , shr (r, x))))
533+ r := or (r, shl (4 , lt (0xffff , shr (r, x))))
534+ r := xor (31 , or (shr (3 , r), lt (0xff , shr (r, x))))
535+ computed := r
536+ }
537+ }
538+ assertEq (computed, expected);
539+ }
396540}
0 commit comments