はじめに
初めまして。
CryptoGamesというブロックチェーンゲーム企業でエンジニアをしている cardene(かるでね) です!
スマートコントラクトを書いたり、フロントエンド・バックエンド・インフラと幅広く触れています。
代表的なゲームはクリプトスペルズというブロックチェーンゲームです。
今回は、Ethereumでの大文字と小文字が混在するアドレスのチェックサムの仕組みを提案している規格であるEIP55についてまとめていきます!
以下にまとめられているものを翻訳・要約・補足しながらまとめていきます。
他にも様々なERCについてまとめています。
仕様
import eth_utils
def checksum_encode(addr): # Takes a 20-byte binary address as input
hex_addr = addr.hex()
checksummed_buffer = ""
# Treat the hex address as ascii/utf-8 for keccak256 hashing
hashed_address = eth_utils.keccak(text=hex_addr).hex()
# Iterate over each character in the hex address
for nibble_index, character in enumerate(hex_addr):
if character in "0123456789":
# We can't upper-case the decimal digits
checksummed_buffer += character
elif character in "abcdef":
# Check if the corresponding hex digit (nibble) in the hash is 8 or higher
hashed_address_nibble = int(hashed_address[nibble_index], 16)
if hashed_address_nibble > 7:
checksummed_buffer += character.upper()
else:
checksummed_buffer += character
else:
raise eth_utils.ValidationError(
f"Unrecognized hex character {character!r} at position {nibble_index}"
)
return "0x" + checksummed_buffer
def test(addr_str):
addr_bytes = eth_utils.to_bytes(hexstr=addr_str)
checksum_encoded = checksum_encode(addr_bytes)
assert checksum_encoded == addr_str, f"{checksum_encoded} != expected {addr_str}"
test("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed")
test("0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359")
test("0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB")
test("0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb")
このコードは、イーサリアム(Ethereum)のアドレスをチェックサムエンコードするためのPython関数と、それをテストするための関数を提供しています。
以下の手順に従ってコードの機能と動作を詳細に説明します。
checksum_encode
-
checksum_encode
関数は、20
バイトのバイナリアドレスを受け取り、チェックサム付きの形式で表現します。 - まず、入力のバイナリアドレスを
16
進数文字列に変換します(addr.hex()
を使用)。 - 次に、
16
進数文字列をUTF-8エンコードしたものとして扱い、それをkeccak256
ハッシュ関数を用いてハッシュ化します。- このハッシュ化は、アドレスのチェックサム計算に使用されます。
- その後、
16
進数文字列を一文字ずつ処理します。- 各文字に対して以下の条件分岐を行います。
- 数字(
0
から9
)の場合- 文字をそのまま追加します。
- 小文字の
16
進数文字(a
からf
)の場合- 対応するハッシュ値の対応するニブル(
4
ビット単位)が8
以上の場合、大文字に変換して追加し、そうでない場合は小文字のまま追加します。 - これにより、チェックサムの計算に寄与する文字を大文字で表現します。
- 対応するハッシュ値の対応するニブル(
- 上記以外の文字の場合
- エラーを発生させます。
- これにより、アドレス文字列が
16
進数の文字以外を含む場合にエラーが報告されます。
- 最終的に、すべての文字を処理したら、0xを接頭辞としてチェックサムエンコードされたアドレス文字列を返します。
test
-
test
関数は、アドレス文字列を受け取り、それがchecksum_encode
関数によって正しくエンコードされるかをテストします。 - 与えられたアドレス文字列を
16
進数のバイト列に変換し、checksum_encode
関数を呼び出してチェックサムエンコードを行います。 - チェックサムエンコードされたアドレス文字列が元のアドレス文字列と一致しない場合、アサーションエラーが発生し、エラーメッセージが表示されます。
最後に、提供されたテストケースでtest
関数が呼び出されており、各アドレス文字列が正しくチェックサムエンコードされるかどうかを確認しています。
このコードは、Ethereumのアドレス文字列のチェックサムを計算するために使用できるユーティリティ関数を提供し、それが正しく機能することを確認するテストも提供しています。
この要求に基づいて、アドレスを16進数文字列に変換し、特定の条件に従って大文字または小文字で出力するプロセスを説明します。
また、指定された条件に従った例も示します。
- アドレスを
16
進数文字列に変換します。- 例
- アドレス
0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed
は5aaeb6053f3e94c9b9a09f33669435e7ef1beaed
に変換されます。
- アドレス
- 例
-
16
進数文字列を小文字に変換し、UTF-8エンコードして、keccak256
ハッシュ関数を使用してハッシュ値を計算します。- 例
- ハッシュ化により、バイナリ表現
0010 1101 1000 0000 0101 1111 0010 0001 ...
が得られます。
- ハッシュ化により、バイナリ表現
- 例
- ハッシュ値の各ビットを調べ、
4
ビットごとに文字を処理します。 - 各文字が数字(
0
から9
)である場合、そのまま出力します。- 例
-
5
は数字であるため、そのまま出力されます。
-
- 例
- 各文字が小文字の
16
進数文字(a
からf
)である場合、対応するハッシュ値の4
ビット目(0
から3
のビット位置)を確認します。- 4ビット目が
1
であれば、その文字を大文字で出力し、0
であれば小文字で出力します。 - 例1
-
a
は小文字であり、ハッシュ値の4
ビット目が1
であるため、大文字で出力されます(A
)。
-
- 例2
-
f
は小文字であり、ハッシュ値の4
ビット目が0
であるため、小文字で出力されます(f
)。
-
- 4ビット目が
- 上記の条件に当てはまらない場合、そのまま出力します。
上記のプロセスにより、指定された条件に基づいて、アドレスの各16
進数文字が大文字または小文字で正確に出力されます。
特定の言葉や略語についても、指定された条件に従って変換されます。
補足
利点
- 既存の多くの
16
進数パーサーと互換性があり、大文字と小文字を混在して受け入れることができるため、徐々に導入するのが容易です。- これは、従来の
16
進数アドレス表現と新しいチェックサムエンコード表現の両方が受け入れられることを意味します。
- これは、従来の
- アドレスの長さを
40
文字に保ちます。- アドレスの長さは変わらず、従来の形式と同じ
40
文字です。
- アドレスの長さは変わらず、従来の形式と同じ
- 平均的にアドレスごとに
15
個のチェックビットがあり、ランダムに生成されたアドレスが誤ってチェックを通過する確率は約0.0247%
です。- これはICAPに比べて約
50
倍の改善であり、4
バイトのチェックコードに比べると劣ります。 - チェックサムを使用することで、アドレスの誤りを検出しやすくし、間違って受け入れられる確率を大幅に減少させます。
- ただし、
4
バイトのチェックコードに比べると精度は劣ります。
- これはICAPに比べて約
新しいチェックサムエンコード方法には、アドレス表現の改善に関するいくつかの利点があります。
まず、既存の16
進数パーサーとの互換性を保持し、新しい方法を段階的に導入することが容易です。
また、アドレスの長さは40
文字のままであり、形式の変更が必要ありません。
さらに、アドレスごとに平均的に15
個のチェックビットがあり、ランダムに生成されたアドレスが誤ってチェックを通過する確率は非常に低いため、エラーの検出が向上します。
これにより、アドレスの信頼性が高まりますが、4
バイトのチェックコードに比べるとわずかに劣る精度を持っています。
実装
const createKeccakHash = require('keccak')
function toChecksumAddress (address) {
address = address.toLowerCase().replace('0x', '')
var hash = createKeccakHash('keccak256').update(address).digest('hex')
var ret = '0x'
for (var i = 0; i < address.length; i++) {
if (parseInt(hash[i], 16) >= 8) {
ret += address[i].toUpperCase()
} else {
ret += address[i]
}
}
return ret
}
イーサリアム(Ethereum)のアドレス文字列をチェックサムエンコードするためのJavaScript関数toChecksumAddress
を実装しています。
以下はコードの機能と動作の詳細な説明です。
createKeccakHash
ライブラリのインポート
最初に、createKeccakHash
ライブラリをrequire
を使ってインポートしています。
このライブラリは、Keccak-256ハッシュ関数を提供します。
toChecksumAddress
関数
toChecksumAddress
関数は、チェックサムを適用するためのメインの関数です。
引数として、チェックサムを適用したいアドレス文字列を受け取ります。
アドレスの前処理
関数内で、受け取ったアドレス文字列を小文字に変換し、0xの接頭辞を取り除きます。
これにより、アドレス文字列が小文字で始まることと、接頭辞0xが存在しないことが保証されます。
アドレスのハッシュ化
-
createKeccakHash('keccak256')
を使用して、Keccak-256ハッシュ関数を初期化します。 -
update(address)
メソッドを使用して、前処理されたアドレス文字列をハッシュ関数に渡し、ハッシュ値を計算します。 -
digest('hex')
メソッドを使用して、ハッシュ値を16
進数文字列として取得します。
チェックサムの計算
- ハッシュ値と前処理されたアドレス文字列を比較し、チェックサムを計算します。
-
for
ループを使用して、アドレス文字列の各文字に対して以下の条件分岐を行います。- アドレス文字列の各文字を
16
進数に変換し、10
進数として取得します(parseInt(hash[i], 16)
)。 - 取得した
10
進数が8
以上の場合、対応するアドレス文字を大文字に変換してret
変数に追加します。- これにより、チェックサムの計算に寄与する文字が大文字で表現されます。
- それ以外の場合、アドレス文字をそのまま
ret
変数に追加します。
- アドレス文字列の各文字を
チェックサムエンコードされたアドレスの返却
-
ret
変数にはチェックサムエンコードされたアドレス文字列が含まれています。 - 関数は最終的にこの文字列を
return
して返します。
このコードは、イーサリアムのアドレス文字列にチェックサムを適用し、大文字と小文字を適切に変換して、アドレスの正確性を向上させるためのユーティリティ関数を提供しています。
> toChecksumAddress('0xfb6916095ca1df60bb79ce92ce3ea74c37c5d359')
'0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359'
Keccak-256ハッシュへの入力は、小文字の16
進文字列(つまり、ASCIIとしてエンコードされた16
進アドレス)であることに注意する。
var hash = createKeccakHash('keccak256').update(Buffer.from(address.toLowerCase(), 'ascii')).digest()
テスト
# All caps
0x52908400098527886E0F7030069857D2E4169EE7
0x8617E340B3D01FA5F11F306F4090FD50E238070D
# All Lower
0xde709f2102306220921060314715629080e2fb77
0x27b1fdb04752bbc536007a920d24acb045561c26
# Normal
0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed
0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359
0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB
0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb
引用
Vitalik Buterin vitalik.buterin@ethereum.org, Alex Van de Sande avsa@ethereum.org, "ERC-55: Mixed-case checksum address encoding," Ethereum Improvement Proposals, no. 55, January 2016. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-55.
最後に
今回は「Ethereumでの大文字と小文字が混在するアドレスのチェックサムの仕組みを提案している規格であるEIP55」についてまとめてきました!
いかがだったでしょうか?
質問などがある方は以下のTwitterのDMなどからお気軽に質問してください!
他の媒体でも情報発信しているのでぜひ他も見ていってください!