Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 18805] ファイルの概要

このコミットは、Go言語の標準ライブラリ crypto/md5 および crypto/sha1 パッケージ内のジェネリック(汎用)実装ファイルに対する変更です。具体的には、md5block_generic.gosha1block_generic.go のビルドタグが修正され、amd64p32 アーキテクチャがこれらのジェネリック実装から除外されるようになりました。これにより、amd64p32 向けに最適化されたMD5およびSHA1の実装が存在する場合に、ビルド時の競合やエラーを防ぐことが目的です。

コミット

crypto/md5, crypto/sha1: ジェネリック実装からamd64p32を除外

md5とsha1にはamd64p32の実装が提供されているため、これらのパッケージのジェネリック実装からamd64p32を除外する必要があります。

CL 72360044がマージされた後にビルドを修正します。

LGTM=agl, remyoudompheng R=rsc, bradfitz, agl, remyoudompheng CC=golang-codereviews https://golang.org/cl/72460043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/3d869c6e0c26503f835b4c2694af45e64991c4cd

元コミット内容

commit 3d869c6e0c26503f835b4c2694af45e64991c4cd
Author: Dave Cheney <dave@cheney.net>
Date:   Sat Mar 8 07:54:41 2014 +1100

    crypto/md5, crypto/sha1: exclude amd64p32 from generic implementations.
    
    We provide amd64p32 implementations for md5 and sha1 so we need to exclude amd64p32 from the generic implementations in those packages.
    
    Fixes build once CL 72360044 lands.
    
    LGTM=agl, remyoudompheng
    R=rsc, bradfitz, agl, remyoudompheng
    CC=golang-codereviews
    https://golang.org/cl/72460043

変更の背景

このコミットの主な背景は、Go言語のビルドシステムにおける特定のアーキテクチャ(amd64p32)向けの最適化された暗号化アルゴリズム実装の導入です。

Go言語の標準ライブラリには、様々なアーキテクチャ(例: amd64, 386, arm など)に対応するためのジェネリック(汎用)な実装と、特定のアーキテクチャに特化した最適化された実装の両方が含まれることがあります。最適化された実装は、通常、アセンブリ言語などで記述され、そのアーキテクチャのCPU命令セットを最大限に活用することで、パフォーマンスを向上させます。

コミットメッセージにある「We provide amd64p32 implementations for md5 and sha1」という記述は、amd64p32 という特定のアーキテクチャ向けに、MD5およびSHA1ハッシュアルゴリズムの最適化された実装が別途用意されたことを示唆しています。

Goのビルドシステムでは、ソースファイルの先頭に記述される「ビルドタグ」(+build ディレクティブ)を使用して、特定のファイルがどの環境(OS、アーキテクチャなど)でコンパイルされるべきかを制御します。もし、あるアーキテクチャ向けに最適化された実装と、そのアーキテクチャも対象とするジェネリックな実装の両方が存在すると、コンパイル時に「重複定義」のエラーが発生する可能性があります。

このコミットは、まさにこの問題を解決するために行われました。amd64p32 向けの最適化されたMD5およびSHA1の実装が導入されたため、既存のジェネリック実装ファイルが amd64p32 環境でコンパイルされないように、ビルドタグを修正する必要がありました。

コミットメッセージの「Fixes build once CL 72360044 lands.」という記述は、この変更が、別の変更セット(Change List: CL 72360044)がGoのリポジトリにマージされた後に発生するビルドエラーを修正するためのものであることを明確に示しています。つまり、CL 72360044で amd64p32 向けの最適化された実装が追加され、その結果としてこのコミットが必要になった、という依存関係があります。

前提知識の解説

このコミットを理解するためには、以下の概念について知っておく必要があります。

  1. MD5 (Message-Digest Algorithm 5):

    • MD5は、任意の長さのデータから128ビット(16バイト)のハッシュ値(メッセージダイジェスト)を生成する暗号学的ハッシュ関数です。
    • データの完全性チェックによく使用されますが、衝突耐性(異なる入力から同じハッシュ値が生成される可能性)が弱いため、セキュリティが重要な場面での使用は推奨されません。
  2. SHA-1 (Secure Hash Algorithm 1):

    • SHA-1は、MD5と同様にハッシュ関数ですが、160ビット(20バイト)のハッシュ値を生成します。
    • MD5よりも強力ですが、こちらも衝突攻撃に対する脆弱性が発見されており、現在ではセキュリティが重要な場面での使用は推奨されず、SHA-256やSHA-3などのより強力なハッシュ関数への移行が進んでいます。
  3. 暗号学的ハッシュ関数:

    • 入力データから固定長のハッシュ値を生成する一方向関数です。
    • 主な特性として、以下の点が挙げられます。
      • 一方向性: ハッシュ値から元のデータを復元することは非常に困難です。
      • 衝突耐性: 異なる入力から同じハッシュ値が生成されることが非常に困難です。
      • 改ざん検出: 入力データが少しでも変更されると、ハッシュ値が大きく変化するため、データの改ざんを検出できます。
  4. amd64p32 アーキテクチャ:

    • amd64 は64ビットのx86アーキテクチャを指しますが、amd64p32 は少し特殊な環境を指します。これは、64ビットのCPU上で動作するものの、ポインタのサイズが32ビットである環境を意味します。
    • このような環境は、特定の組み込みシステムや、メモリ使用量を抑えたいが64ビットCPUの恩恵も受けたいといったニッチな用途で利用されることがあります。Go言語は、このような多様な環境への対応を重視しています。
  5. Go言語のビルドタグ (+build ディレクティブ):

    • Go言語のソースファイルの先頭に記述される特殊なコメント行で、そのファイルがどのビルド条件でコンパイルされるかを制御します。
    • 形式は // +build tag1,tag2 !tag3 のようになります。
    • タグは論理AND (tag1,tag2) や論理OR (tag1 tag2) で組み合わせることができ、! を前置することで否定条件を指定できます。
    • 例えば、+build linux,amd64 はLinuxかつamd64アーキテクチャの場合にコンパイルされ、+build !windows はWindows以外のOSでコンパイルされます。
    • これにより、OSやアーキテクチャ、Goのバージョンなどに応じて、異なる実装のファイルを選択的にコンパイルすることが可能になります。これは、クロスプラットフォーム開発や、特定のハードウェアに最適化されたコードを提供するために非常に重要な機能です。
  6. ジェネリック実装と最適化された実装:

    • ジェネリック実装 (Generic Implementation): 多くの異なる環境で動作するように、汎用的なコードで書かれた実装です。通常、Go言語のような高水準言語で記述されます。可読性が高く、移植性が高いという利点がありますが、特定のハードウェアの特性を最大限に活かすことはできません。
    • 最適化された実装 (Optimized Implementation): 特定のCPUアーキテクチャやハードウェアの特性(例: SIMD命令セット、特定のレジスタの使用など)を最大限に活用するために、アセンブリ言語などで書かれた実装です。非常に高速に動作するという利点がありますが、特定の環境に依存するため、移植性が低く、コードの可読性も低下する傾向があります。
    • Go言語では、パフォーマンスが重要な部分(特に暗号化やハッシュ計算など)では、ジェネリック実装と並行して、主要なアーキテクチャ向けに最適化された実装を提供することがよくあります。ビルドタグは、これらの異なる実装の中から、現在のビルド環境に最適なものを選択するために使用されます。

技術的詳細

このコミットの技術的な核心は、Go言語のビルドタグの正確な使用と、それによって実現される条件付きコンパイルのメカニズムにあります。

Goのビルドシステムは、ソースファイルをコンパイルする際に、各ファイルの先頭にある +build ディレクティブを読み取ります。このディレクティブは、そのファイルが現在のビルド環境(オペレーティングシステム、CPUアーキテクチャなど)と一致する場合にのみコンパイル対象に含める、という指示を与えます。

変更前の md5block_generic.gosha1block_generic.go のビルドタグは以下の通りでした。

// +build !amd64,!386,!arm

これは、「amd64386arm のいずれのアーキテクチャでもない場合にこのファイルをコンパイルする」という意味です。つまり、これらの主要なアーキテクチャ向けには、おそらくより最適化された実装が別途存在し、それ以外のアーキテクチャ(例えば、mipsppc64、あるいは汎用的なGoのコードで十分な場合)ではこのジェネリックな実装が使用されることを意図していました。

しかし、amd64p32 向けのMD5およびSHA1の最適化された実装が導入されたことで問題が発生しました。amd64p32amd64 とは異なるものの、上記のビルドタグの条件 !amd64,!386,!arm には合致してしまいます。その結果、amd64p32 環境でビルドを行うと、最適化された amd64p32 固有の実装と、このジェネリックな実装の両方がコンパイル対象となり、同じ関数や変数の重複定義が発生し、ビルドエラーとなる可能性がありました。

このコミットでは、この問題を解決するために、ビルドタグに !amd64p32 を追加しました。

// +build !amd64,!amd64p32,!386,!arm

この変更により、ビルドタグの意味は「amd64amd64p32386arm のいずれのアーキテクチャでもない場合にこのファイルをコンパイルする」となります。これにより、amd64p32 環境でビルドする際には、このジェネリックな実装ファイルはコンパイル対象から除外され、代わりに amd64p32 向けの最適化された実装のみが使用されるようになります。

この修正は、Go言語のクロスコンパイル能力と、多様なアーキテクチャへの対応を維持しつつ、特定の環境で最高のパフォーマンスを提供するための重要な調整です。ビルドタグを適切に管理することで、開発者は異なる環境向けに異なるコードパスを提供し、コンパイル時の競合を避けることができます。

コアとなるコードの変更箇所

このコミットで変更されたファイルは以下の2つです。

  1. src/pkg/crypto/md5/md5block_generic.go
  2. src/pkg/crypto/sha1/sha1block_generic.go

それぞれのファイルで、ビルドタグの行が1行変更されています。

--- a/src/pkg/crypto/md5/md5block_generic.go
+++ b/src/pkg/crypto/md5/md5block_generic.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !amd64,!386,!arm
+// +build !amd64,!amd64p32,!386,!arm
 
 package md5
 
--- a/src/pkg/crypto/sha1/sha1block_generic.go
+++ b/src/pkg/crypto/sha1/sha1block_generic.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !amd64,!386,!arm
+// +build !amd64,!amd64p32,!386,!arm
 
 package sha1
 

コアとなるコードの解説

変更されたのは、各ファイルの2行目にあるビルドタグの行です。

変更前: // +build !amd64,!386,!arm

変更後: // +build !amd64,!amd64p32,!386,!arm

この変更は非常にシンプルですが、その影響は重要です。

  • md5block_generic.gosha1block_generic.go は、それぞれMD5とSHA1のハッシュ計算におけるブロック処理のジェネリック(汎用)な実装を含んでいます。これらのファイルは、特定のアーキテクチャ向けに最適化されたアセンブリコードなどが存在しない場合にフォールバックとして使用されます。
  • 元のビルドタグ !amd64,!386,!arm は、「amd64386arm のいずれのアーキテクチャでもない場合にこのファイルをコンパイルする」という意味でした。これは、これらの主要なアーキテクチャには、より高速な専用実装があるため、ジェネリック実装は不要であることを示しています。
  • 新しく amd64p32 向けのMD5およびSHA1の最適化された実装が追加されたため、amd64p32 環境でビルドする際に、このジェネリック実装が誤ってコンパイルされてしまう問題が発生しました。amd64p32amd64 とは異なるため、元のタグでは除外されなかったのです。
  • そこで、ビルドタグに !amd64p32 を追加することで、「amd64amd64p32386arm のいずれのアーキテクチャでもない場合にこのファイルをコンパイルする」という条件に変更されました。
  • これにより、amd64p32 環境でビルドする際には、このジェネリックな md5block_generic.go および sha1block_generic.go ファイルはコンパイル対象から適切に除外され、amd64p32 固有の最適化された実装が優先的に使用されるようになります。
  • この修正によって、重複定義によるビルドエラーが解消され、Go言語のビルドシステムが意図通りに、各アーキテクチャに最適な実装を選択できるようになりました。

関連リンク

参考にした情報源リンク