Skip to content

Commit

Permalink
Add read signature parts
Browse files Browse the repository at this point in the history
  • Loading branch information
Agusx1211 committed Jan 23, 2024
1 parent 905bfe6 commit 6a242a4
Show file tree
Hide file tree
Showing 4 changed files with 243 additions and 16 deletions.
2 changes: 1 addition & 1 deletion contracts/modules/utils/L2Compressor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ contract L2SequenceDecompressor {
uint256 internalThreshold = bytesToUint256(data);

(data, newPointer) = readSignatureBranch(newPointer);
data = abi.encodePacked(uint8(SequenceBaseSig.FLAG_NESTED), uint8(externalWeight), uint8(internalThreshold), uint24(data.length), data);
data = abi.encodePacked(uint8(SequenceBaseSig.FLAG_NESTED), uint8(externalWeight), uint16(internalThreshold), uint24(data.length), data);

return (data, newPointer);

Expand Down
16 changes: 16 additions & 0 deletions foundry_test/modules/utils/L2CompressorEncoder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -255,3 +255,19 @@ function encode_address(uint8 _weight, address _addr) pure returns (bytes memory

return abi.encodePacked(uint8(0x3b), uint8(_weight), encodeWord(uint256(uint160(_addr))));
}

function encode_node(bytes32 _node) pure returns (bytes memory) {
return abi.encodePacked(uint8(0x40), encodeWord(_node));
}

function encode_branch(bytes memory _nested) pure returns (bytes memory) {
return abi.encodePacked(uint8(0x41), encode_bytes_n(_nested));
}

function encode_subdigest(bytes32 _subdigest) pure returns (bytes memory) {
return abi.encodePacked(uint8(0x42), encodeWord(_subdigest));
}

function encode_nested(uint8 _weight, uint8 _threshold, bytes memory _nested) pure returns (bytes memory) {
return abi.encodePacked(uint8(0x43), uint8(_weight), uint8(_threshold), encode_bytes_n(_nested));
}
64 changes: 64 additions & 0 deletions foundry_test/modules/utils/L2CompressorHuffReadFlag.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -436,4 +436,68 @@ contract L2CompressorHuffReadFlagTests is AdvTest {

assertEq(res, abi.encodePacked(uint8(1), _weight, _addr));
}

function test_read_node(bytes32 _node) external {
bytes memory encoded = encode_node(_node);

(bool s, bytes memory r) = imp.staticcall(encoded);

assertTrue(s);

(uint256 rindex, uint256 windex, bytes memory res) = abi.decode(r, (uint256, uint256, bytes));

assertEq(rindex, encoded.length);
assertEq(windex, FMS + res.length);

assertEq(res, abi.encodePacked(uint8(3), _node));
}

function test_read_subdigest(bytes32 _subdigest) external {
bytes memory encoded = encode_subdigest(_subdigest);

(bool s, bytes memory r) = imp.staticcall(encoded);

assertTrue(s);

(uint256 rindex, uint256 windex, bytes memory res) = abi.decode(r, (uint256, uint256, bytes));

assertEq(rindex, encoded.length);
assertEq(windex, FMS + res.length);

assertEq(res, abi.encodePacked(uint8(5), _subdigest));
}

function test_read_branch(bytes memory _data) external {
vm.assume(_data.length <= type(uint24).max);

bytes memory encoded = encode_branch(_data);

(bool s, bytes memory r) = imp.staticcall(encoded);

assertTrue(s);

(uint256 rindex, uint256 windex, bytes memory res) = abi.decode(r, (uint256, uint256, bytes));

assertEq(rindex, encoded.length);
assertEq(windex, FMS + res.length);

assertEq(res, abi.encodePacked(uint8(4), uint24(_data.length), _data));
}

function test_read_nested(uint8 _weight, uint8 _threshold, bytes memory _data) external {
vm.assume(_data.length <= type(uint24).max);

bytes memory encoded = encode_nested(_weight, _threshold, _data);

(bool s, bytes memory r) = imp.staticcall(encoded);

assertTrue(s);

(uint256 rindex, uint256 windex, bytes memory res) = abi.decode(r, (uint256, uint256, bytes));

assertEq(rindex, encoded.length);
assertEq(windex, FMS + res.length);

assertEq(res, abi.encodePacked(uint8(6), uint8(_weight), uint16(_threshold), uint24(_data.length), _data));
}
}
177 changes: 162 additions & 15 deletions src/L2Compressor.huff
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,15 @@
FLAG_ADDRESS_W0 // 0x3b
FLAG_ADDRESS_W1 // 0x3c
FLAG_ADDRESS_W2 // 0x3d
FLAG_ADDRESS_W3 // 0x3f
FLAG_ADDRESS_W4 // 0x40
FLAG_ADDRESS_W3 // 0x3e
FLAG_ADDRESS_W4 // 0x4f
FLAG_NODE // 0x40
FLAG_BRANCH // 0x41
FLAG_SUBDIGEST // 0x42
FLAG_NESTED // 0x43
}

#define constant HIGHEST_FLAG = 0x40
#define constant HIGHEST_FLAG = 0x44

#define macro READ_FLAG() = takes (2) returns (2) {
nrfs:
Expand Down Expand Up @@ -395,6 +399,19 @@
READ_ADDRESS_WX(nrfs, 0x04) // [windex, rindex]
end jump

FLAG_NODE:
READ_NODE(nrfs) // [windex, rindex]
end jump
FLAG_BRANCH:
READ_BRANCH(nrfs) // [windex, rindex]
end jump
FLAG_SUBDIGEST:
READ_SUBDIGEST(nrfs) // [windex, rindex]
end jump
FLAG_NESTED:
READ_NESTED(nrfs) // [windex, rindex]
end jump // [end jump, windex, rindex]

default:
// The default just pushes the flag as a byte (padded to 32 bytes)
// notice that we start at 0x01 since 0x00 can be pushed with the flag 0x00
Expand Down Expand Up @@ -530,12 +547,7 @@
#define macro READ_SIGNATURE() = takes (3) returns (2) {
// input stack: [windex, rindex, weight]

// First thing we must write is the flag (sequence)

0x00 // [0x00, windex, rindex, weight]
dup2 // [windex, 0x00, windex, rindex, weight]
mstore // [windex, rindex, weight]
0x01 add // [windex, rindex, weight]
WRITE_SEQUENCE_FLAG(0x00)

// Second thing we must write is the weight, always 1 byte

Expand Down Expand Up @@ -593,12 +605,7 @@
#define macro READ_ADDRESS(nrfs) = takes (3) returns (2) {
// input stack: [windex, rindex, weight]

// First thing we must write is the flag (sequence)

0x01 // [0x01, windex, rindex, weight]
dup2 // [windex, 0x01, windex, rindex, weight]
mstore8 // [windex, rindex, weight]
0x01 add // [windex, rindex, weight]
WRITE_SEQUENCE_FLAG(0x01)

// Second thing we must write is the weight, always 1 byte

Expand All @@ -623,6 +630,146 @@
0x14 add // [windex + 0x14, rindex]
}

#define macro READ_NODE(nrfr) = takes (2) returns (2) {
// input stack: [windex, rindex]

WRITE_SEQUENCE_FLAG(0x03)

// Now we just proceed by reading another flag

PERFORM_NESTED_READ_FLAG(nrfs) // [windex, rindex]

// output stack: [windex, rindex]
}

#define macro READ_BRANCH(nrfr) = takes (2) returns (2) {
// input stack: [windex, rindex]

WRITE_SEQUENCE_FLAG(0x04)

// Now we just proceed by reading the branch
// the only important part is that we need to
// measure how much is written, as the branch is
// always prefixed by the size

// Clear the memory here, that way we don't need to mask it
// when we write the size
callvalue // [0x00, windex, rindex]
dup2 mstore // [windex, rindex]

// Reserve 3 bytes for the size
dup1 // [windex, size_pointer, rindex]
0x03 add // [windex, size_pointer, rindex]

swap2 // [rindex, size_pointer, windex]
dup3 // [windex, rindex, size_pointer, prev_windex]

PERFORM_NESTED_READ_FLAG(nrfs) // [windex, rindex, size_pointer, prev_windex]

// Need to go back and write the size now

swap3 // [prev_windex, rindex, size_pointer, windex]
dup4 // [windex, prev_windex, rindex, size_pointer, windex]
sub // [size, rindex, size_pointer, windex]
0xe8 shl // [size << 0xe8, rindex, size_pointer, windex]
dup3 // [size_pointer, size, rindex, size_pointer, windex]
mload // [mload[size_pointer], size, rindex, size_pointer, windex]
or // [(mload[size_pointer] | size), rindex, size_pointer, windex]
swap1 // [rindex, (mload[size_pointer] | size), size_pointer, windex]
swap2 // [size_pointer, (mload[size_pointer] | size), rindex, windex]
mstore // [rindex, windex]
swap1 // [windex, rindex]

// output stack: [windex, rindex]
}

#define macro READ_SUBDIGEST(nrfr) = takes (2) returns (2) {
// input stack: [windex, rindex]

WRITE_SEQUENCE_FLAG(0x05)

// Now we just proceed by reading another flag

PERFORM_NESTED_READ_FLAG(nrfs) // [windex, rindex]

// output stack: [windex, rindex]
}


#define macro READ_NESTED(nrfr) = takes (2) returns (2) {
// input stack: [windex, rindex]

WRITE_SEQUENCE_FLAG(0x06) // [windex, rindex]

// Read the weight and the threshold
// the weight is always 1 byte, the threshold uses 2
// but in reality most Sequence wallets use 1, so this library
// only supports 1 byte for it. If the wallet is not compatible, READ_NESTED
// can't be used, and READ_N_BYTES must be used instead

swap1 // [rindex, windex]
LOAD_DYNAMIC_SIZE(0x01, 0xf8) // [weight, rindex, windex]
swap1 // [rindex, weight, windex]
LOAD_DYNAMIC_SIZE(0x01, 0xf8) // [threshold, rindex, weight, windex]
0xf0 shl // [threshold << 0xf0, rindex, weight, windex]
swap2 // [weight, rindex, threshold, windex]

dup4 // [windex, weight, rindex, threshold, windex]
mstore8 // [rindex, threshold, windex]
swap2 // [windex, threshold, rindex]
0x01 add // [windex, threshold, rindex]
swap1 // [threshold, windex, rindex]
dup2 // [windex, threshold, windex, rindex]
mstore // [windex, rindex]
0x02 add // [windex, rindex]

// Now we just proceed by reading the branch
// the only important part is that we need to
// measure how much is written, as the branch is
// always prefixed by the size

// Clear the memory here, that way we don't need to mask it
// when we write the size
callvalue // [0x00, windex, rindex]
dup2 mstore // [windex, rindex]

// Reserve 3 bytes for the size
dup1 // [windex, size_pointer, rindex]
0x03 add // [windex, size_pointer, rindex]

swap2 // [rindex, size_pointer, windex]
dup3 // [windex, rindex, size_pointer, prev_windex]

PERFORM_NESTED_READ_FLAG(nrfs) // [windex, rindex, size_pointer, prev_windex]

// Need to go back and write the size now

swap3 // [prev_windex, rindex, size_pointer, windex]
dup4 // [windex, prev_windex, rindex, size_pointer, windex]
sub // [size, rindex, size_pointer, windex]
0xe8 shl // [size << 0xe8, rindex, size_pointer, windex]
dup3 // [size_pointer, size, rindex, size_pointer, windex]
mload // [mload[size_pointer], size, rindex, size_pointer, windex]
or // [(mload[size_pointer] | size), rindex, size_pointer, windex]
swap1 // [rindex, (mload[size_pointer] | size), size_pointer, windex]
swap2 // [size_pointer, (mload[size_pointer] | size), rindex, windex]
mstore // [rindex, windex]
swap1 // [windex, rindex]

// output stack: [windex, rindex]
}

#define macro WRITE_SEQUENCE_FLAG(flag) = takes (2) returns (2) {
// input stack: [windex, rindex]

<flag> // [flag, windex, rindex]
dup2 // [windex, flag, windex, rindex]
mstore8 // [windex, rindex]
0x01 add // [windex, rindex]

// output stack: [windex, rindex]
}

#[calldata("0x02f1f2")]
#define test TEST_READ_FLAG_2_BYTES() = {
0x00 // [rindex]
Expand Down

0 comments on commit 6a242a4

Please sign in to comment.