Skip to content

Commit 53b5d84

Browse files
authored
Add bytes6 to the Packing library. (#5077)
1 parent dc62599 commit 53b5d84

File tree

5 files changed

+329
-32
lines changed

5 files changed

+329
-32
lines changed

contracts/utils/Packing.sol

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,24 @@ library Packing {
4545
}
4646
}
4747

48+
function pack_2_4(bytes2 left, bytes4 right) internal pure returns (bytes6 result) {
49+
assembly ("memory-safe") {
50+
result := or(left, shr(16, right))
51+
}
52+
}
53+
54+
function pack_2_6(bytes2 left, bytes6 right) internal pure returns (bytes8 result) {
55+
assembly ("memory-safe") {
56+
result := or(left, shr(16, right))
57+
}
58+
}
59+
60+
function pack_4_2(bytes4 left, bytes2 right) internal pure returns (bytes6 result) {
61+
assembly ("memory-safe") {
62+
result := or(left, shr(32, right))
63+
}
64+
}
65+
4866
function pack_4_4(bytes4 left, bytes4 right) internal pure returns (bytes8 result) {
4967
assembly ("memory-safe") {
5068
result := or(left, shr(32, right))
@@ -87,6 +105,18 @@ library Packing {
87105
}
88106
}
89107

108+
function pack_6_2(bytes6 left, bytes2 right) internal pure returns (bytes8 result) {
109+
assembly ("memory-safe") {
110+
result := or(left, shr(48, right))
111+
}
112+
}
113+
114+
function pack_6_6(bytes6 left, bytes6 right) internal pure returns (bytes12 result) {
115+
assembly ("memory-safe") {
116+
result := or(left, shr(48, right))
117+
}
118+
}
119+
90120
function pack_8_4(bytes8 left, bytes4 right) internal pure returns (bytes12 result) {
91121
assembly ("memory-safe") {
92122
result := or(left, shr(64, right))
@@ -255,6 +285,48 @@ library Packing {
255285
}
256286
}
257287

288+
function extract_6_1(bytes6 self, uint8 offset) internal pure returns (bytes1 result) {
289+
if (offset > 5) revert OutOfRangeAccess();
290+
assembly ("memory-safe") {
291+
result := and(shl(mul(8, offset), self), shl(248, not(0)))
292+
}
293+
}
294+
295+
function replace_6_1(bytes6 self, bytes1 value, uint8 offset) internal pure returns (bytes6 result) {
296+
bytes1 oldValue = extract_6_1(self, offset);
297+
assembly ("memory-safe") {
298+
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
299+
}
300+
}
301+
302+
function extract_6_2(bytes6 self, uint8 offset) internal pure returns (bytes2 result) {
303+
if (offset > 4) revert OutOfRangeAccess();
304+
assembly ("memory-safe") {
305+
result := and(shl(mul(8, offset), self), shl(240, not(0)))
306+
}
307+
}
308+
309+
function replace_6_2(bytes6 self, bytes2 value, uint8 offset) internal pure returns (bytes6 result) {
310+
bytes2 oldValue = extract_6_2(self, offset);
311+
assembly ("memory-safe") {
312+
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
313+
}
314+
}
315+
316+
function extract_6_4(bytes6 self, uint8 offset) internal pure returns (bytes4 result) {
317+
if (offset > 2) revert OutOfRangeAccess();
318+
assembly ("memory-safe") {
319+
result := and(shl(mul(8, offset), self), shl(224, not(0)))
320+
}
321+
}
322+
323+
function replace_6_4(bytes6 self, bytes4 value, uint8 offset) internal pure returns (bytes6 result) {
324+
bytes4 oldValue = extract_6_4(self, offset);
325+
assembly ("memory-safe") {
326+
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
327+
}
328+
}
329+
258330
function extract_8_1(bytes8 self, uint8 offset) internal pure returns (bytes1 result) {
259331
if (offset > 7) revert OutOfRangeAccess();
260332
assembly ("memory-safe") {
@@ -297,6 +369,20 @@ library Packing {
297369
}
298370
}
299371

372+
function extract_8_6(bytes8 self, uint8 offset) internal pure returns (bytes6 result) {
373+
if (offset > 2) revert OutOfRangeAccess();
374+
assembly ("memory-safe") {
375+
result := and(shl(mul(8, offset), self), shl(208, not(0)))
376+
}
377+
}
378+
379+
function replace_8_6(bytes8 self, bytes6 value, uint8 offset) internal pure returns (bytes8 result) {
380+
bytes6 oldValue = extract_8_6(self, offset);
381+
assembly ("memory-safe") {
382+
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
383+
}
384+
}
385+
300386
function extract_12_1(bytes12 self, uint8 offset) internal pure returns (bytes1 result) {
301387
if (offset > 11) revert OutOfRangeAccess();
302388
assembly ("memory-safe") {
@@ -339,6 +425,20 @@ library Packing {
339425
}
340426
}
341427

428+
function extract_12_6(bytes12 self, uint8 offset) internal pure returns (bytes6 result) {
429+
if (offset > 6) revert OutOfRangeAccess();
430+
assembly ("memory-safe") {
431+
result := and(shl(mul(8, offset), self), shl(208, not(0)))
432+
}
433+
}
434+
435+
function replace_12_6(bytes12 self, bytes6 value, uint8 offset) internal pure returns (bytes12 result) {
436+
bytes6 oldValue = extract_12_6(self, offset);
437+
assembly ("memory-safe") {
438+
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
439+
}
440+
}
441+
342442
function extract_12_8(bytes12 self, uint8 offset) internal pure returns (bytes8 result) {
343443
if (offset > 4) revert OutOfRangeAccess();
344444
assembly ("memory-safe") {
@@ -395,6 +495,20 @@ library Packing {
395495
}
396496
}
397497

498+
function extract_16_6(bytes16 self, uint8 offset) internal pure returns (bytes6 result) {
499+
if (offset > 10) revert OutOfRangeAccess();
500+
assembly ("memory-safe") {
501+
result := and(shl(mul(8, offset), self), shl(208, not(0)))
502+
}
503+
}
504+
505+
function replace_16_6(bytes16 self, bytes6 value, uint8 offset) internal pure returns (bytes16 result) {
506+
bytes6 oldValue = extract_16_6(self, offset);
507+
assembly ("memory-safe") {
508+
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
509+
}
510+
}
511+
398512
function extract_16_8(bytes16 self, uint8 offset) internal pure returns (bytes8 result) {
399513
if (offset > 8) revert OutOfRangeAccess();
400514
assembly ("memory-safe") {
@@ -465,6 +579,20 @@ library Packing {
465579
}
466580
}
467581

582+
function extract_20_6(bytes20 self, uint8 offset) internal pure returns (bytes6 result) {
583+
if (offset > 14) revert OutOfRangeAccess();
584+
assembly ("memory-safe") {
585+
result := and(shl(mul(8, offset), self), shl(208, not(0)))
586+
}
587+
}
588+
589+
function replace_20_6(bytes20 self, bytes6 value, uint8 offset) internal pure returns (bytes20 result) {
590+
bytes6 oldValue = extract_20_6(self, offset);
591+
assembly ("memory-safe") {
592+
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
593+
}
594+
}
595+
468596
function extract_20_8(bytes20 self, uint8 offset) internal pure returns (bytes8 result) {
469597
if (offset > 12) revert OutOfRangeAccess();
470598
assembly ("memory-safe") {
@@ -549,6 +677,20 @@ library Packing {
549677
}
550678
}
551679

680+
function extract_24_6(bytes24 self, uint8 offset) internal pure returns (bytes6 result) {
681+
if (offset > 18) revert OutOfRangeAccess();
682+
assembly ("memory-safe") {
683+
result := and(shl(mul(8, offset), self), shl(208, not(0)))
684+
}
685+
}
686+
687+
function replace_24_6(bytes24 self, bytes6 value, uint8 offset) internal pure returns (bytes24 result) {
688+
bytes6 oldValue = extract_24_6(self, offset);
689+
assembly ("memory-safe") {
690+
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
691+
}
692+
}
693+
552694
function extract_24_8(bytes24 self, uint8 offset) internal pure returns (bytes8 result) {
553695
if (offset > 16) revert OutOfRangeAccess();
554696
assembly ("memory-safe") {
@@ -647,6 +789,20 @@ library Packing {
647789
}
648790
}
649791

792+
function extract_28_6(bytes28 self, uint8 offset) internal pure returns (bytes6 result) {
793+
if (offset > 22) revert OutOfRangeAccess();
794+
assembly ("memory-safe") {
795+
result := and(shl(mul(8, offset), self), shl(208, not(0)))
796+
}
797+
}
798+
799+
function replace_28_6(bytes28 self, bytes6 value, uint8 offset) internal pure returns (bytes28 result) {
800+
bytes6 oldValue = extract_28_6(self, offset);
801+
assembly ("memory-safe") {
802+
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
803+
}
804+
}
805+
650806
function extract_28_8(bytes28 self, uint8 offset) internal pure returns (bytes8 result) {
651807
if (offset > 20) revert OutOfRangeAccess();
652808
assembly ("memory-safe") {
@@ -759,6 +915,20 @@ library Packing {
759915
}
760916
}
761917

918+
function extract_32_6(bytes32 self, uint8 offset) internal pure returns (bytes6 result) {
919+
if (offset > 26) revert OutOfRangeAccess();
920+
assembly ("memory-safe") {
921+
result := and(shl(mul(8, offset), self), shl(208, not(0)))
922+
}
923+
}
924+
925+
function replace_32_6(bytes32 self, bytes6 value, uint8 offset) internal pure returns (bytes32 result) {
926+
bytes6 oldValue = extract_32_6(self, offset);
927+
assembly ("memory-safe") {
928+
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
929+
}
930+
}
931+
762932
function extract_32_8(bytes32 self, uint8 offset) internal pure returns (bytes8 result) {
763933
if (offset > 24) revert OutOfRangeAccess();
764934
assembly ("memory-safe") {

scripts/generate/templates/Packing.js

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,43 +36,51 @@ pragma solidity ^0.8.20;
3636
`;
3737

3838
const errors = `\
39-
error OutOfRangeAccess();`;
39+
error OutOfRangeAccess();
40+
`;
4041

41-
const pack = (left, right) => `
42+
const pack = (left, right) => `\
4243
function pack_${left}_${right}(bytes${left} left, bytes${right} right) internal pure returns (bytes${
4344
left + right
4445
} result) {
4546
assembly ("memory-safe") {
4647
result := or(left, shr(${8 * left}, right))
4748
}
48-
}`;
49+
}
50+
`;
4951

50-
const extract = (outer, inner) => `
52+
const extract = (outer, inner) => `\
5153
function extract_${outer}_${inner}(bytes${outer} self, uint8 offset) internal pure returns (bytes${inner} result) {
5254
if (offset > ${outer - inner}) revert OutOfRangeAccess();
5355
assembly ("memory-safe") {
5456
result := and(shl(mul(8, offset), self), shl(${256 - 8 * inner}, not(0)))
5557
}
56-
}`;
58+
}
59+
`;
5760

58-
const replace = (outer, inner) => `
61+
const replace = (outer, inner) => `\
5962
function replace_${outer}_${inner}(bytes${outer} self, bytes${inner} value, uint8 offset) internal pure returns (bytes${outer} result) {
6063
bytes${inner} oldValue = extract_${outer}_${inner}(self, offset);
6164
assembly ("memory-safe") {
6265
result := xor(self, shr(mul(8, offset), xor(oldValue, value)))
6366
}
64-
}`;
67+
}
68+
`;
6569

6670
// GENERATE
6771
module.exports = format(
6872
header.trimEnd(),
6973
'library Packing {',
70-
errors,
71-
product(SIZES, SIZES)
72-
.filter(([left, right]) => SIZES.includes(left + right))
73-
.map(([left, right]) => pack(left, right)),
74-
product(SIZES, SIZES)
75-
.filter(([outer, inner]) => outer > inner)
76-
.flatMap(([outer, inner]) => [extract(outer, inner), replace(outer, inner)]),
74+
format(
75+
[].concat(
76+
errors,
77+
product(SIZES, SIZES)
78+
.filter(([left, right]) => SIZES.includes(left + right))
79+
.map(([left, right]) => pack(left, right)),
80+
product(SIZES, SIZES)
81+
.filter(([outer, inner]) => outer > inner)
82+
.flatMap(([outer, inner]) => [extract(outer, inner), replace(outer, inner)]),
83+
),
84+
).trimEnd(),
7785
'}',
7886
);
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
const { range } = require('../../helpers');
2-
3-
const SIZES = range(1, 33).filter(size => size == 1 || size == 2 || size % 4 == 0);
4-
5-
module.exports = { SIZES };
1+
module.exports = {
2+
SIZES: [1, 2, 4, 6, 8, 12, 16, 20, 24, 28, 32],
3+
};

scripts/generate/templates/Packing.t.js

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,39 @@ import {Test} from "forge-std/Test.sol";
1010
import {Packing} from "@openzeppelin/contracts/utils/Packing.sol";
1111
`;
1212

13-
const testPack = (left, right) => `
13+
const testPack = (left, right) => `\
1414
function testPack(bytes${left} left, bytes${right} right) external {
1515
assertEq(left, Packing.pack_${left}_${right}(left, right).extract_${left + right}_${left}(0));
1616
assertEq(right, Packing.pack_${left}_${right}(left, right).extract_${left + right}_${right}(${left}));
17-
}`;
17+
}
18+
`;
1819

19-
const testReplace = (outer, inner) => `
20+
const testReplace = (outer, inner) => `\
2021
function testReplace(bytes${outer} container, bytes${inner} newValue, uint8 offset) external {
2122
offset = uint8(bound(offset, 0, ${outer - inner}));
2223
2324
bytes${inner} oldValue = container.extract_${outer}_${inner}(offset);
2425
2526
assertEq(newValue, container.replace_${outer}_${inner}(newValue, offset).extract_${outer}_${inner}(offset));
2627
assertEq(container, container.replace_${outer}_${inner}(newValue, offset).replace_${outer}_${inner}(oldValue, offset));
27-
}`;
28+
}
29+
`;
2830

2931
// GENERATE
3032
module.exports = format(
31-
header.trimEnd(),
32-
'',
33+
header,
3334
'contract PackingTest is Test {',
34-
' using Packing for *;',
35-
product(SIZES, SIZES)
36-
.filter(([left, right]) => SIZES.includes(left + right))
37-
.map(([left, right]) => testPack(left, right)),
38-
product(SIZES, SIZES)
39-
.filter(([outer, inner]) => outer > inner)
40-
.map(([outer, inner]) => testReplace(outer, inner)),
35+
format(
36+
[].concat(
37+
'using Packing for *;',
38+
'',
39+
product(SIZES, SIZES)
40+
.filter(([left, right]) => SIZES.includes(left + right))
41+
.map(([left, right]) => testPack(left, right)),
42+
product(SIZES, SIZES)
43+
.filter(([outer, inner]) => outer > inner)
44+
.map(([outer, inner]) => testReplace(outer, inner)),
45+
),
46+
).trimEnd(),
4147
'}',
4248
);

0 commit comments

Comments
 (0)