solidity バイト処理まとめ
solidityのbyte周りが苦手なのでまとめました。
低レイヤーの実装をするようになると頻繁に利用するようになるので、solidityのエンジニアには必須の知識です。
ちなみにsolidityの実装にAIを使うと、ほぼ100%の確率で適当なコードを吐き出してくる(要はネットに出回っているコードが間違いだらけ)ので、現時点でのAIの利用はやめましょう。
環境
- solidity ^0.8.19
- hardhat
bytes1~bytes32
1バイトから32バイトまでのバイト列を保持できます。
非常に低コストなので、バイト長を制限できるならば、bytesではなくbytes1~bytes32を利用した方が良いです。
まずはbytes1
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.19;
import "hardhat/console.sol";
contract Study {
function test() public {
bytes1 data1 = 0xff;
console.logBytes1(data1); // 0xff
}
}
接頭の0xは16進数を表しています。
hardhatのlogで出力を確認したい場合はconsole.logBytes1(data1);のようにします。
次にbytes16
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.19;
import "hardhat/console.sol";
contract Study {
function test() public {
bytes1 data1 = 0xff;
bytes16 data16 = 0xffaabbccddeeff112233445566778899;
console.logBytes1(data1); // 0xff
console.logBytes16(data16); // 0xffaabbccddeeff112233445566778899
}
}
hardhatのlogで出力を確認したい場合はconsole.logBytes16(data16);のようにします。
bytes1~bytes32 length
lengthでサイズを取得できます。
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.19;
import "hardhat/console.sol";
contract Study {
function test() public {
bytes1 data1 = 0xff;
bytes16 data16 = 0xffaabbccddeeff112233445566778899;
console.logBytes1(data1); // 0xff
console.logBytes16(data16); // 0xffaabbccddeeff112233445566778899
console.log(data1.length); // 1
console.log(data16.length); // 16
}
}
indexで要素にアクセス
indexを使ってbyteの配列に格納できます。
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.19;
import "hardhat/console.sol";
contract Study {
function test() public {
bytes1 data1 = 0xff;
bytes16 data16 = 0xffaabbccddeeff112233445566778899;
console.logBytes1(data1); // 0xff
console.logBytes16(data16); // 0xffaabbccddeeff112233445566778899
console.log(data1.length); // 1
console.log(data16.length); // 16
console.logBytes1(data1[0]); // 0xff
console.logBytes1(data16[1]); // 0xaa
}
}
bytes
byte大きさがわからない時はbytesを使います。
大きさがわからないので、関数の引数に使います。
bytesはeth.jsのencodeFunctionData等の関数で作成できます。
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.19;
import "hardhat/console.sol";
contract Study {
function test2(bytes calldata initCode) public {
console.log("initCode");
console.logBytes(initCode); // 0xf8a8fd6d
console.logBytes(initCode[0 : 3]); // 0xf8a8fd
console.logBytes20(bytes20(initCode[0 : 3])); // 0xf8a8fd0000000000000000000000000000000000
}
}
上記では引数のbytesが4byteで、bytes20を使うことで20バイトのデータにしています。
bytes20を呼び出すと、右側を0paddingで埋めます。
addressは20バイトなので、addressとしても利用できます。
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.19;
import "hardhat/console.sol";
contract Study {
function test2(bytes calldata initCode) public {
console.log("initCode");
console.logBytes(initCode); // 0xf8a8fd6d
console.logBytes(initCode[0 : 3]); // 0xf8a8fd
console.logBytes20(bytes20(initCode[0 : 3])); // 0xf8a8fd0000000000000000000000000000000000
address factory = address(bytes20(initCode[0 : 3]));
console.log("address");
console.log(factory); // 0xf8a8fd0000000000000000000000000000000000
}
}
この辺は低レイヤーの実装でよく使うので理解しておきましょう。
keccak256
文字列をbytes32にするにはkeccak256を使います。
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.19;
import "hardhat/console.sol";
contract Study {
function test2(bytes calldata initCode) public {
bytes32 b32str = keccak256("hello");
console.logBytes32(b32str); // 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8
}
}
abi.encodePacked
abi.encodePackedはBytesを返します。
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.19;
import "hardhat/console.sol";
contract Study {
function test2(bytes calldata initCode) public {
console.logBytes(abi.encodePacked("hello")); // 0x68656c6c6f
}
}
認証ではkeccak256と一緒に使ってメッセージのハッシュを作成します。
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.19;
import "hardhat/console.sol";
contract Study {
function test2(bytes calldata initCode) public {
console.logBytes32(keccak256(abi.encodePacked("hello"))); // 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8
}
}
署名の場合には以下のように実装します。
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.19;
import "hardhat/console.sol";
contract Study {
function test2(bytes calldata initCode) public {
console.logBytes32(keccak256(
abi.encodePacked("\x19Ethereum Signed Message:\n32", keccak256(abi.encodePacked("hello")))
)); // 0x456e9aea5e197a1f1af7a3e85a3212fa4049a3ba34c2289b4c860fc0b0c64ef3
}
}
参考記事
Discussion