go-ethereumの暗号ライブラリ活用戦略
ブロックチェーンで活用される暗号技術や、Ethereumのアーキテクチャについて学び、理解を深めることを目的に、Ethereumの最初の実装の1つであり最も使われテストされているクライアント go-ethereum から得られた知見をこの記事にしました。
本記事では、暗号ライブラリは何がどのように使われているのか、という切り口からコードリーディングを行い、解説しています。
記事の内容に不備等あれば是非フィードバックいただきたいです。
概要
- go-ethereumにおけるパッケージの活用方法は2通り。直接importして利用するか、ラップしたライブラリを go-ehtereum/crypto に実装して使うか。
- プリコンパイルドコントラクトの機能など、一部独自に実装されているものもあるが、ほとんどの暗号技術はGoの標準や準標準の暗号ライブラリを基盤として機能しており、実績のあるライブラリを再利用することで、安全性や性能と、開発容易性を両立している
go-ethereumで暗号技術が使われる場面
Ethereumは分散型アプリケーションやスマートコントラクトのプラットフォームであり、暗号技術が重要な役割を果たしています。
go-ethereumで暗号技術が使用されている主要な用途を紹介します。
キーペアによるアカウントの管理
Ethereumの各アカウントは、公開鍵と秘密鍵のペアによって識別されます。
公開鍵はアドレスとして活用され、秘密鍵はトランザクションの署名や鍵の管理に使用されます。
これらのキーペアの生成や管理には、secp256k1と呼ばれる楕円曲線暗号の技術が利用されています。
トランザクションの署名
ブロックチェーンでは、トランザクションの発行者が正当であることを確認するためにデジタル署名が使用されます。
Ethereumは、署名アルゴリズムとしてECDSAを採用しており、秘密鍵を用いてトランザクションに署名を行います。
また、公開鍵を使って署名の検証が行われます。
ハッシュ関数の利用
Ethereumでは、ハッシュ関数がさまざまな場面で利用されます。
例
- トランザクションやブロックのハッシュ値の計算
- マークル・パトリシア・ツリーの構築
go-ethereumでは、効率的なハッシュ関数であるKeccak256(SHA-3)やBLAKE2bが利用されています。
セキュアな乱数生成
暗号技術では、鍵の生成や一部のアルゴリズムで乱数が必要となります。
安全な乱数生成は、暗号技術全体のセキュリティに大きく影響します。
go-ethereumでは、セキュアな乱数生成アルゴリズムが実装されており、鍵ペアの生成や一時的な秘密鍵の生成など、様々な場面で使用されます。
P2P通信の暗号化
Ethereumネットワークは、ピア・ツー・ピア(P2P)でノード間の通信が行われます。
このP2P通信においても、暗号技術がデータのプライバシー保護や通信のセキュリティを確保するために使用されています。
go-ethereumでは、The RLPx Transport Protocolと呼ばれるP2P通信のためのTCPベースのトランスポートプロトコルの実現に、楕円曲線暗号を用いた公開鍵暗号であるECIESが利用されています。
プリコンパイルドコントラクト(Precompiled Contracts)
プリコンパイルドコントラクトとは、特定の計算タスクを効率的に実行するための特殊なスマートコントラクトです。
これらのコントラクトは、EVMによってネイティブに実行されるため、通常のスマートコントラクトよりもガスコストが削減され、ブロックチェーン上での処理も高速に動作します。
プリコンパイルドコントラクトとして、SHA256やBN-256、BLS12-381などの機能が提供されており、分散型アプリケーションの開発者はこれらを活用することが出来ます。
go-ethereumで使われている暗号ライブラリ
標準パッケージ crypto
Go の標準パッケージです。
go-ethereumでは、cryptoパッケージ配下にある以下のパッケージが利用されていることを確認しました。
pkg | godocの説明 |
---|---|
aes | aesパッケージは、米国連邦情報処理基準(FIPS)Publication 197に定義されているAES暗号化(旧Rijndael)を実装します。 |
cipher | cipherパッケージは、低レベルのブロック暗号実装をラップできる標準ブロック暗号モードを実装します。 |
ecdsa | ecdsaパッケージは、FIPS 186-4およびSEC 1バージョン2.0で定義されている楕円曲線デジタル署名アルゴリズムを実装します。 |
ed25519 | ed25519パッケージは、Ed25519署名アルゴリズムを実装します。 |
elliptic | ellipticパッケージは、素数体上の標準的なNIST P-224, P-256, P-384, P-521楕円曲線を実装します。 |
hmac | hmacパッケージは、米国連邦情報処理基準(FIPS)Publication 198で定義されているキー付きハッシュメッセージ認証コード(HMAC)を実装します。 |
rand | randパッケージは、暗号学的に安全な乱数生成器を実装します。 |
sha256 | sha256パッケージは、FIPS 180-4で定義されているSHA224およびSHA256ハッシュアルゴリズムを実装します。 |
sha512 | sha512パッケージは、FIPS 180-4で定義されているSHA-384、SHA-512、SHA-512/224、およびSHA-512/256ハッシュアルゴリズムを実装します。 |
subtle | subtleパッケージは、暗号コードで役立つことが多いが、正しく使用するために慎重な考慮が必要な関数を実装します。 |
golang.org/x/crypto
準標準パッケージの位置付けである、golang.org/x/crypto(GitHub)のライブラリも利用されています。
go-ethereumでは、以下のパッケージが利用されていることを確認しました。
pkg | godocの説明 |
---|---|
hkdf | hkdfパッケージは、RFC 5869で定義されたHMACベースの抽出・拡張キー導出関数(HKDF)を実装します。 |
openpgp | openpgpパッケージは、OpenPGPメッセージに対する高レベルな操作を実装します。 |
pbkdf2 | pbkdf2パッケージは、RFC 2898 / PKCS #5 v2.0で定義されたキー導出関数PBKDF2を実装します。 |
ripemd160 | ripemd160パッケージは、RIPEMD-160ハッシュアルゴリズムを実装します。 |
scrypt | scryptパッケージは、Colin Percivalの論文「Stronger Key Derivation via Sequential Memory-Hard Functions」で定義されたscryptキー導出関数を実装します。 |
sha3 | sha3パッケージは、FIPS-202によって定義されたSHA-3固定出力長ハッシュ関数とSHAKE可変出力長ハッシュ関数を実装します。 |
btcsuite/btcd, bitcoin-core/secp256k1
Ethereumのキーペアの生成や管理に使われる楕円曲線暗号 secp256k1 は、Bitcoinとまったく同じものが使われており、Bitcoin の楕円曲線ライブラリを再利用することで実現されています。
Goで実装されたBitcoinノードであるbtcsuite/btcdのライブラリが使われていますが、cgo が有効な場合は bitcoin-core/secp256k1 を使った実装に切り替わります
consensys/gnark-crypto
MetaMaskで有名なConsenSysが提供するライブラリ consensys/gnark-crypto も、fuzzing testの用途のみですが利用されています。
利用されている箇所
- https://github.com/ethereum/go-ethereum/blob/v1.11.6/tests/fuzzers/bn256/bn256_fuzz.go#L28
- https://github.com/ethereum/go-ethereum/blob/v1.11.6/tests/fuzzers/bls12381/bls12381_fuzz.go#L29-L32
パッケージの活用方法
go-ethereumにおけるパッケージの活用方法は主に2通り存在します。
1つ目は、必要な場面で直接importして使う方法です。
パッケージの機能をシンプルに使いたい場合はこの方法が使われています。
2つ目はパッケージをラップした実装を go-ethereum/crypto に置く方法です。
ライブラリを使わずに実現されているアルゴリズム(BLS12-381やECIESなど)や、go-ethereumでの利用のために既存パッケージをラップして調整されたものはこの go-ethereum/cryptoに置かれています。
go-ethereum/crypto 配下の pkg
pkg | 説明 |
---|---|
blake2b | BLAKE2bは、高速でセキュアな暗号ハッシュ関数です。 golang.org/x/crypto でもパッケージが提供されていますが、プリコンパイルドコントラクトに最適化したものが独自に実装されています。(PR) |
bls12381 | BLS12-381は、効率的なペアリングベースの暗号技術の実装です。プリコンパイルドコントラクトの実装に利用されています。 |
bn256 | 楕円曲線暗号を使用した古典的なペアリングベースの暗号技術 BN-256 の実装です。golang.org/x/crypto でもパッケージが提供されていますが、ガスコスト改善のためcloudflareのライブラリを参考にした実装に切り替えられました(PR)。ちなみに、golang.org/x/crypto/bn256 は現在非推奨になっています。(https://github.com/golang/go/issues/30141) |
ecies | ECIES(Elliptic Curve Integrated Encryption Scheme)と呼ばれる、楕円曲線暗号を用いた公開鍵暗号です。標準のcryptoパッケージを組み合わせて実現されており、P2P通信に利用されています。 |
secp256k1 | キーペアの生成などで利用される楕円曲線暗号アルゴリズムの実装です。Bitcoin のライブラリを再利用していますが、cgoの利用可否で利用ライブラリをハンドリングする必要があるため、ラッパーが実装されています。 |
signify | crypto/ed25519 をラップして実装された署名機能の実装です。 |
【おまけ】EIP-4844について
つい先日正式に実装することが決まった EIP-4844: Protodank Shardingですが、こちらで提案されているKZGと呼ばれる暗号も、紹介した go-ethereum/crypto に実装される予定です。
secp256k1と同じようにcgoの有無でライブラリを切り替える実装になっており、cgoが無効な場合は crate-crypto/go-kzg-4844、有効な場合はethereum/c-kzg-4844を使うようになっています。
興味がある方はコードを読んでみてください。
まとめ
本記事では、go-ethereumの暗号ライブラリ活用戦略という切り口からコードリーディングを行い、得られた知識を紹介しました。
go-ethereumにおけるパッケージの活用方法としては、直接importして利用する方法と、それらをラップして独自ライブラリを実装する方法が存在し、用途に応じて使い方が変わることがわかります。
コードを読んでいて気づいたのは、プリコンパイルドコントラクトの機能など、一部独自に実装されているものもありますが、ほとんどの暗号技術はGoの標準や準標準の暗号ライブラリを基盤として機能しているということです。
実績のあるライブラリを再利用することで、安全性や性能と、開発容易性を両立していることがわかります。
今回はgo-ethereumのみについての紹介でしたが、他のブロックチェーンとの方針の違いなども気になるところです。
最後に宣伝ですが、6/2に開催予定のGo Conference 2023 に「Goはブロックチェーン領域でなぜ使われ、どのように活躍しているのか」というセッションタイトルで登壇予定です。ブロックチェーン領域でGoがなぜ利用されるのかを解説し、具体的にどのようにブロックチェーンの技術を支えているのかを実際のコードを見ながら紹介します。
Room Aにて16:30から登壇予定ですので、興味がある方は是非チェックいただければと思います。
Discussion