web3 学習: キー、アドレス

イーサリアムの基盤となるテクノロジーの 1 つ コンピューター セキュリティで広く使用されている数学の一分野である暗号化です。暗号化はギリシャ語で「秘密の書き込み」を意味しますが、暗号化の科学には秘密の共同作業以上のものが含まれており、暗号化と呼ばれています。暗号化は、秘密を明らかにせずに知識を証明したり (デジタル署名)、データの信頼性を証明したり (デジタル指紋) するためにも使用できます。これらのタイプの暗号証明は、イーサリアムとほとんどのブロックチェーン システムの重要な数学的ツールであり、イーサリアム アプリケーションで広く使用されています。皮肉なことに、暗号化は Ethereum の重要な部分ではありません。その通信とトランザクション データは暗号化されておらず、システムを保護するために暗号化を必要としないからです。この章では、イーサリアムが鍵とアドレスの形で資金の所有権を制御するために使用する暗号化のいくつかを紹介します。

序章

イーサリアムには、イーサを所有および管理できる 2 種類のアカウントがあります。それは、外部所有アカウント(EOA) と _contracts_ です。このセクションでは、外部で所有されているアカウント (つまり、秘密鍵) によるイーサの所有権を決定するための暗号化の使用について調べます。

EOA における Ether の所有権は、デジタル キーEthereum アドレス、およびデジタル署名によって確立されます。デジタルキーは、実際にはブロックチェーンに保存されたり、イーサリアムネットワークに送信されたりするのではなく、ユーザーによって作成され、_wallets_ と呼ばれるファイルまたは単純なデータベースに保存されます。ユーザーのウォレットのデジタルキーは、Ethereum プロトコルから完全に独立しており、ブロックチェーンやインターネットへのアクセスを参照せずに、ユーザーのウォレット ソフトウェアによって生成および管理できます。デジタルキーは、分散型の信頼と管理、所有権の証明など、イーサリアムの興味深い特性の多くを可能にします。

イーサリアム トランザクションでは、有効なデジタル署名がブロックチェーンに含まれている必要がありますが、これはキーを使用してのみ生成できます。したがって、そのキーのコピーを持っている人は誰でもイーサを制御できます。Ethereum トランザクションのデジタル署名は、資金の真の所有者を証明します。

デジタル鍵は、秘密鍵と公開鍵のペアで構成されています。公開鍵は銀行の口座番号に相当し、秘密鍵は口座を管理するために使用される秘密の PIN に相当すると考えてください。イーサリアムのユーザーがこれらのデジタル キーを目にすることはめったにありません。ほとんどの場合、それらはウォレット ファイル内に保存され、イーサリアム ウォレット ソフトウェアによって管理されます。

Ethereum トランザクションの支払い部分では、対象の受取人は _Ethereum address_ で表されます。これは、小切手の受取人の名前 (つまり、「誰に」) と同じです。ほとんどの場合、Ethereum アドレスは公開鍵から生成され、公開鍵に対応します。ただし、すべての Ethereum アドレスが公開鍵を表しているわけではありません。[contract]で説明するように、それらはコントラクトを表すこともできますEthereum アドレスは、ユーザーが世界と共有する必要があるため、ユーザーが頻繁に目にする唯一のキーの表現です。

まず、暗号を紹介し、イーサリアムで使用される数学について説明します。次に、キーがどのように生成、保存、および管理されるかを見ていきます。最後に、秘密鍵と公開鍵、およびアドレスを表すために使用されるさまざまなエンコード形式を確認します。

公開鍵暗号と暗号通貨

公開鍵暗号化は、最新の情報セキュリティの中核となる概念です。1970 年代に Martin Hellman、Whitfield Diffie、および Ralph Merkle によって最初に公に発明された暗号は、暗号化の分野で広く一般の関心を呼び起こす大きなブレークスルーでした。1970 年代以前は、暗号に関する強力な知識が政府の管理下にあり、公開鍵暗号に関する研究が発表されるまで、公的研究はほとんど行われませんでした。

公開キー暗号化では、一意のキーを使用して情報を保護します。これらの一意のキーは、一意のプロパティを持つ数学関数に基づいています。一方向の計算は簡単ですが、反対方向の計算は困難です。これらの数学関数に基づいて、暗号化はデジタル鍵の作成と、数学の法則によって保証される偽造不可能なデジタル署名を可能にします。

たとえば、2 つの大きな素数の積を計算するのは簡単です。しかし、2 つの大きな素数の積が与えられた場合、これら 2 つの素数を見つけるのは非常に困難です (_素因数分解_問題と呼ばれます)。私が 6895601 という数字を提供し、それが 2 つの素数の積であると伝えたとします。これら 2 つの素数を見つけるのは、それらを掛け合わせて 6895601 を生成するよりもはるかに困難です。

これらの数学関数は、秘密の情報を知っていれば簡単に逆にすることができます。上記の例で、主素数の 1 つが 1931 であるとすれば、簡単な除算でもう 1 つを見つけることができます: 6895601/1931 = 3571. このような関数は、_trapdoor 関数_ と呼ばれます。これは、シークレットが与えられた場合、関数を簡単に元に戻すショートカットを使用できるためです。

暗号化に役立つ別のクラスの数学関数は、楕円曲線の算術演算に基づいています。楕円曲線演算では、掛け算のモジュロは単純ですが、割り算はできません (_離散対数_として知られる問題)。楕円曲線暗号は、最新のコンピューター システムで広く使用されており、イーサリアム (およびその他の暗号通貨) のデジタル キーとデジタル署名の基礎となっています。

ヒント

暗号化と現代の暗号化で使用される数学関数の詳細:

暗号化: https://en.wikipedia.org/wiki/Cryptography

トラップドア機能: https://en.wikipedia.org/wiki/Trapdoor_function

素因数分解: https://en.wikipedia.org/wiki/Integer_factorization

離散対数: https://en.wikipedia.org/wiki/Discrete_logarithm

楕円曲線暗号: https://en.wikipedia.org/wiki/Elliptic_curve_cryptography

イーサリアムでは、公開鍵暗号化を使用して、イーサへのアクセスを制御し、契約を認証できるようにする鍵ペアを作成します。キー ペアは、秘密キーと一意の公開キーで構成され、公開キーが秘密キーから派生するため、"ペア" と見なされます。公開鍵は資金を受け取るために使用され、秘密鍵は資金を支払うトランザクションに署名するためのデジタル署名を作成するために使用されます。デジタル署名は、<<contract_authentication>> で説明するように、コントラクトの所有者またはユーザーを認証するためにも使用できます。

公開鍵と秘密鍵の間には数学的関係があり、秘密鍵を使用してメッセージの署名を生成できます。この署名は、秘密鍵を明かさずに公開鍵を使用して検証できます。

イーサを使用する場合、現在の所有者は自分の公開鍵と署名 (毎回異なりますが、同じ秘密鍵で作成されたもの) をトランザクションで提示します。公開鍵と署名を通じて、イーサリアム システム内の誰もがトランザクションの有効性を独自に検証して受け入れることができるため、イーサを転送している人が誰であろうとトランザクションの所有者であることを確認できます。

ヒント

ほとんどのウォレットの実装では、便宜上、秘密鍵と公開鍵が _キー ペア_ として一緒に保存されます。ただし、公開鍵は秘密鍵から簡単に計算できるため、秘密鍵のみを格納することも可能です。

なぜ非対称暗号化 (公開鍵/秘密鍵) を使用するのですか?

イーサリアムで非対称暗号が使用されるのはなぜですか? 「暗号化された」(機密)トランザクションには使用されません。代わりに、非対称暗号化の便利な特性は、デジタル署名を作成できることです。秘密鍵を使用して、トランザクションのデジタル署名を生成できます。この署名は、秘密鍵を知っている人だけが作成できます。ただし、公開鍵とトランザクション署名にアクセスできる人は誰でも、それらを使用して検証できます。非対称暗号化のこの便利な特性により、誰でもすべてのトランザクションのすべての署名を検証できます。

秘密鍵

秘密鍵は、ランダムに選択された番号です。秘密鍵の所有権と管理は、ユーザーが対応する Ethereum アドレスに関連付けられたすべての資金を管理するための基礎であり、アドレスのコントラクトへのアクセスの承認でもあります。秘密鍵は、トランザクションで使用される資金の所有権を証明することにより、イーサを使用するために必要な署名を作成するために使用されます。秘密鍵は常に秘密にしておく必要があります。第三者に鍵を公開することは、その鍵によって保護されたイーサとコントラクトの制御権を第三者に与えることに等しいからです。秘密鍵もバックアップして、偶発的な損失から保護する必要があります。紛失して回復できない場合、それが保護する資金は永久に失われます。

ヒント

イーサリアムの秘密鍵は単なる数字です。コイン、鉛筆、紙を使って秘密鍵をランダムに選ぶことができます。コインを 256 回投げて、イーサリアム ウォレットで秘密鍵として使用できるランダムな 2 進数を取得します。次に、秘密鍵から公開鍵とアドレスを生成できます。

乱数から秘密鍵を生成

キーを生成する最初の最も重要なステップは、エントロピーまたはランダム性の安全なソースを見つけることです。イーサリアム秘密鍵の作成は基本的に「1から2 256までの数字を選ぶ」と同じです。その数を選択するために使用される正確な方法は、予測可能で再現可能でない限り重要ではありません。Ethereum ソフトウェアは、基盤となるオペレーティング システムの乱数ジェネレーターを使用して、256 ビットのエントロピー (乱数) を生成します。通常、OS の乱数ジェネレーターはランダム性の人為的なソースによって初期化されます。そのため、マウスを数秒間左右に動かしたり、キーボードのランダムなキーを押したりするよう求められる場合があります。

より正確には、可能な秘密鍵の範囲は 2 256よりわずかに小さくなります。イーサリアムでは、秘密鍵は +1+ から +n-1+ までの任意の数にすることができます。n は、使用される楕円曲線の次数として定義される定数です (n = 1.158*10 77 、2 256 よりわずか小さい) (楕円曲線暗号の説明を参照してください)。このようなキーを作成するには、256 ビットの数値をランダムに選択し、それが +n-1+ より小さいかどうかを確認します。プログラミング用語では、これは通常、暗号学的に安全なランダム性のソースから収集されたランダム ビットのより大きな文字列を Keccak-256 や SHA256 ([cryptographic_hash_algorithm] を参照) などの 256 ビット ハッシュ アルゴリズムに供給し、256 ビットを生成することによって行われます。番号。結果が +n-1+ 未満の場合、適切な秘密鍵があります。それ以外の場合は、別の乱数で再試行します。

警告

独自のコードを記述して乱数を作成したり、プログラミング言語が提供する「単純な」乱数ジェネレーターを使用したりしないでください。暗号的に安全な疑似乱数ジェネレーター (CSPRNG) と、十分なエントロピーのソースからのシードを使用します。選択した乱数発生器ライブラリのドキュメントを調べて、暗号的に安全であることを確認してください。CSPRNG の適切な実装は、キーのセキュリティにとって重要です。

以下は、ランダムに生成された秘密鍵 (k) を 16 進形式で表示したものです (256 ビット、各 4 桁の 16 進数 64 桁として表示)。

f8f8a2f43c8376ccb0871305060d7b27b0554d2cc72bccf41b2705608452f315

ヒント

イーサリアムの秘密鍵空間のサイズ (2 256 ) は信じられないほど大きい数です。10 進数は約 10 77です。目に見える宇宙には、推定 10 80個の原子が含まれています。

公開鍵

イーサリアムの公開鍵は、楕円曲線上のです。つまり、楕円曲線の方程式を満たす X 座標と Y 座標のセットです。

簡単に言えば、イーサリアムの公開鍵は、並列に連結された 2 つの数値です。これらの数値は、秘密鍵から一方向の計算で生成されます。これは、秘密鍵を持っている場合、公開鍵の計算は簡単であることを意味します。ただし、公開鍵から秘密鍵を計算することはできません。

数学が始まろうとしています! パニックにならない。前の段落が読みにくい場合は、次のいくつかのセクションをスキップできます。計算を行うツールやライブラリは数多くあります。

公開鍵は、楕円曲線の乗算と非可逆な秘密鍵を使用して計算されます: K = k * G、ここで、_k_ は秘密鍵、G_ は _generator point_ と呼ばれる定数ポイント、および _K_ は結果の公開鍵です。_K を知っている場合、「離散対数を見つける」と呼ばれる逆操作は、 _k_ のすべての可能な値を試すのと同じくらい困難です。これは、総当たり検索とも呼ばれます。

簡単に言えば、楕円曲線の算術は「通常の」整数算術とは異なります。ポイント (G) に整数 (k) を掛けると、別のポイント (K) を生成できます。しかし、_除算_というものは存在しないため、単純に公開鍵 K を点 G で割って秘密鍵 k を計算することはできません。これは、Public Key Cryptography and Cryptocurrencyで説明されている一方向の数学関数です。

ヒント

楕円曲線の乗算は、暗号学者が「一方向」関数と呼ぶものです。一方向 (乗算) は簡単に実行できますが、反対方向 (除算) は実行できません。秘密鍵の所有者は、簡単に公開鍵を作成し、それを世界と共有することができます。誰も関数を逆にして公開鍵から秘密鍵を計算することはできないことを知っています. この数学的トリックは、Ethereum 資金の所有権と契約の管理を証明する、偽造不可能で安全なデジタル署名の基礎となります。

秘密鍵から公開鍵を生成する方法を説明する前に、楕円曲線暗号を見てみましょう。

楕円曲線暗号の説明

楕円曲線暗号は、楕円曲線の加算および乗算演算などの離散対数問題に基づく非対称または公開鍵暗号システムです。

楕円曲線の視覚化は、イーサリアムで使用されるものと同様の楕円曲線の一例です。

ヒント

Ethereum は、secp256k1 と呼ばれる、Bitcoin とまったく同じ楕円曲線を使用します。これにより、Bitcoin の楕円曲線ライブラリとツールの多くを再利用できます。

図 1. 楕円曲線の視覚化

イーサリアムは、国立標準技術研究所 (NIST) によって secp256k1 と呼ばれる標準で定義された、特定の楕円曲線と一連の数学定数を使用します。secp256k1 曲線は、楕円曲線を生成する次の関数によって定義されます。

\[\begin{equation} {y^2 = (x^3 + 7)}~\text{over}~(\mathbb{F}_p) \end{equation}\]

また

\[\begin{式} {y^2 \mod p = (x^3 + 7) \mod p} \end{式}\]

mod p (模素数p) 表示该曲线在素数阶_p_的有限域上,也写作 \(\( \mathbb{F}_p \)\), 其中 p = 2256 – 232 – 29 – 28 – 27 – 26 – 24 – 1, 一个非常大的素数。

因为这条曲线是在有限的素数阶上而不是在实数上定义的,所以它看起来像是一个散布在二维中的点的模式,使得难以可视化。然而,数学与实数上的椭圆曲线的数学是相同的。作为一个例子,Elliptic curve cryptography: visualizing an elliptic curve over F(p), with p=17 在一个更小的素数阶17的有限域上显示了相同的椭圆曲线,显示了一个网格上的点的图案。secp256k1 以太坊椭圆曲线可以被认为是一个更复杂的模式,在一个不可思议的大网格上的点。

Figure 2. Elliptic curve cryptography: visualizing an elliptic curve over F(p), with p=17

例如,以下是坐标为(x,y)的点Q,它是 secp256k1 曲线上的一个点:

Q = (49790390825249384486033144355916864607616083520101638681403973749255924539515, 59574132161899900045862086493921015780032175291755807399284007721050341297360)

Using Python to confirm that this point is on the elliptic curve 显示了如何使用Python检查它。变量x和y是上述点Q的坐标。变量p是椭圆曲线的主要阶数(用于所有模运算的素数)。Python的最后一行是椭圆曲线方程(Python中的%运算符是模运算符)。如果x和y确实是椭圆曲线上的点,那么它们满足方程,结果为零(0L+是零值的长整数)。通过在命令行上键入+python 并复制下面的每行(不包括提示符 >>>),亲自尝试一下:

Example 1. Using Python to confirm that this point is on the elliptic curve

Python 3.4.0 (default, Mar 30 2014, 19:23:13)

[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.38)] on darwin

Type "help", "copyright", "credits" or "license" for more information.

>>> p =115792089237316195423570985008687907853269984665640564039457584007908834671663

>>> x =49790390825249384486033144355916864607616083520101638681403973749255924539515

>>> y =59574132161899900045862086493921015780032175291755807399284007721050341297360

>>> (x **3+7- y**2) % p

0L

椭圆曲线算术运算

很多椭圆曲线数学看起来很像我们在学校学到的整数算术。具体而言,我们可以定义一个加法运算符,而不是添加数字就是在曲线上添加点。一旦我们有了加法运算符,我们也可以定义一个点和一个整数的乘法,等于重复加法。

A lot of elliptic curve math looks and works very much like the integer arithmetic we learned at school. Specifically, we can define an addition operator, which instead of adding numbers is adding points on the curve. Once we have the addition operator, we can also define multiplication of a point and a whole number, such that it is equivalent to repeated addition.

加法定义为给定椭圆曲线上的两个点 P1 and P2 , 第三个点 P3 = P1 + P2, 也在椭圆曲线上。

在几何上,这个第三点 P3 是通过在 P1 和 P2 之间画一条直线来计算的。这条线将在另外一个地方与椭圆曲线相交。称此点为 P3' = (x, y)。然后在x轴上反射得到 P3 = (x, –y)。

在椭圆曲线数学中,有一个叫做“无穷点”的点,它大致对应于零点的作用。在计算机上,它有时用 x = y = 0表示(它不满足椭圆曲线方程,但它是一个容易区分的情况,可以检查)。有几个特殊情况解释了“无穷点”的需要。

如果 P1 和 P2 是同一点,P1 and P2 之间的直线应该延伸到曲线上 P1 的切线。 该切线恰好与曲线在一个新点相交。你可以使用微积分技术来确定切线的斜率。我们将我们的兴趣局限在具有两个整数坐标的曲线上,这些技巧令人好奇地工作!

在某些情况下(即,如果 P1 和 P2 具有相同的x值但不同的y值),切线将精确地垂直,在这种情况下P3 =“无穷点”。

如果 P1 是“无穷点”,那么 P1 + P2 = P2。 类似地, 如果 P2 是“无穷点”,P1 + P2 = P1。这显示了无穷点如何扮演零在“正常”算术中扮演的角色。

+ 是可结合的, (A + B) + C = A + (B + C). 这表示 A + B + C 不加括号也没有歧义。

现在我们已经定义了加法,我们可以用扩展加法的标准方式来定义乘法。对于椭圆曲线上的点P,如果k是整数,则 k * P = P + P + P + … + P (k 次)。请注意,在这种情况下,k有时会被混淆地称为“指数”。

生成一个公钥

以一个随机生成的数字_k_的私钥开始,我们通过将它乘以称为_generator point_ G_的曲线上的预定点,在曲线上的其他位置产生另一个点,这是相应的公钥_K。生成点被指定为+secp256k1+标准的一部分,对于+secp256k1+的所有实现始终相同,并且从该曲线派生的所有密钥都使用相同的点_G_:

\[\begin{equation} {K = k * G} \end{equation}\]

其中_k_是私钥,G_是生成点,_K_是生成的公钥,即曲线上的一个点。因为所有以太坊用户的生成点始终相同,所以_G_乘以_G_的私钥总是会导致相同的公钥_Kk_和_K_之间的关系是固定的,但只能从_k_到_K_的一个方向进行计算。这就是为什么以太坊地址(来自_K)可以与任何人共享,并且不会泄露用户的私钥(k)。

正如我们在 椭圆曲线算术运算中所描述的那样,k * G的乘法相当于重复加,G + G + G + … + G ,重复k次。总而言之,为了从私钥_k_生成公钥_K_,我们将生成点_G_添加到自己_k_次。

Tip

私钥可以转换为公钥,但公钥不能转换回私钥,因为数学只能单向工作。

让我们应用这个计算来找到我们在 私钥 中给出的特定私钥的公钥:

Example private key to public key calculation

K = f8f8a2f43c8376ccb0871305060d7b27b0554d2cc72bccf41b2705608452f315 * G

密码库可以帮助我们使用椭圆曲线乘法计算K值。得到的公钥_K_被定义为一个点 K = (x,y) :

Example public key calculated from the example private key

K = (x, y)

where,

x = 6e145ccef1033dea239875dd00dfb4fee6e3348b84985c92f103444683bae07b

y = 83b5c38e5e2b0c8529d7fa3f64d46daa1ece2d9ac14cab9477d042c84c32ccd0

在以太坊中,你可以看到公钥以66个十六进制字符(33字节)的十六进制序列表示。这是从行业联盟标准高效密码组(SECG)提出的标准序列化格式采用的,在http://www.secg.org/sec1-v2.pdf[Standards for Efficient Cryptography(SEC1)]中有记载。该标准定义了四个可用于识别椭圆曲线上点的可能前缀:

Prefix

Meaning

Length (bytes counting prefix)

0x00

Point at Infinity

1

0x04

Uncompressed Point

65

0x02

Compressed Point with even Y

33

0x03

Compressed Point with odd Y

33

以太坊只使用未压缩的公钥,因此唯一相关的前缀是(十六进制)04。顺序连接公钥的X和Y坐标:

04 + X-coordinate (32 bytes/64 hex) + Y coordinate (32 bytes/64 hex)

因此,我们在 Example public key calculated from the example private key 中计算的公钥被序列化为:

046e145ccef1033dea239875dd00dfb4fee6e3348b84985c92f103444683bae07b83b5c38e5e2b0c8529d7fa3f64d46daa1ece2d9ac14cab9477d042c84c32ccd0

椭圆曲线库

加密货币相关项目中使用了secp256k1椭圆曲线的几个实现:

OpenSSL

OpenSSL库提供了一套全面的加密原语,包括secp256k1的完整实现。例如,要派生公钥,可以使用函数+EC_POINT_mul()+。https://www.openssl.org/

libsecp256k1

Bitcoin Core的libsecp256k1是secp256k1椭圆曲线和其他密码原语的C语言实现。椭圆曲线密码学的libsecp256是从头开始编写的,代替了Bitcoin Core软件中的OpenSSL,在性能和安全性方面被认为是优越的。https://github.com/bitcoin-core/secp256k1

加密哈希函数

加密哈希函数在整个以太坊使用。事实上,哈希函数几乎在所有密码系统中都有广泛应用,这是密码学家布鲁斯•施奈尔(Bruce Schneier)所说的一个事实,他说:“单向哈希函数远不止于加密算法,而是现代密码学的主要工具。

在本节中,我们将讨论哈希函数,了解它们的基本属性以及这些属性如何使它们在现代密码学的很多领域如此有用。我们在这里讨论哈希函数,因为它们是将以太坊公钥转换成地址的一部分。

简而言之,“哈希函数是可用于将任意大小的数据映射到固定大小的数据的函数。” Source:Wikipedia。哈希函数的输入称为 原象 _ pre-image_ 或 消息 message。输出被称为 哈希 hash_或 _摘要 digest。哈希函数的一个特殊子类别是 加密哈希函数,它具有对密码学有用的特定属性。

加密哈希函数是一种_单向_哈希函数,它将任意大小的数据映射到固定大小的位串,如果知道输出,计算上不可能重新创建输入。确定输入的唯一方法是对所有可能的输入进行蛮力搜索,检查匹配输出。

加密哈希函数有五个主要属性 (Source: Wikipedia/Cryptographic Hash Function):

确定性

任何输入消息总是产生相同的哈希摘要。

可验证性

计算消息的哈希是有效的(线性性能)。

不相关

对消息的小改动(例如,一位改变)会大幅改变哈希输出,以致它不能与原始消息的哈希相关联。

不可逆性

从哈希计算消息是不可行的,相当于通过可能的消息进行蛮力搜索。

碰撞保护

计算两个不同的消息产生相同的哈希输出应该是不可行的。

碰撞保护对于防止以太坊中的数字签名伪造至关重要。

这些属性的组合使加密哈希函数可用于广泛的安全应用程序,包括:

  • 数据指纹识别

  • 消息完整性(错误检测)

  • 工作证明

  • 认证(密码哈希和密钥扩展)

  • 伪随机数发生器

  • 原象承诺

  • 唯一标识符

通过研究系统的各个层面,我们会在以太坊找到它的很多应用。

以太坊的加密哈希函数 - Keccak-256

以太坊在许多地方使用_Keccak-256_加密哈希函数。Keccak-256被设计为于2007年举行的SHA-3密码哈希函数竞赛的候选者。Keccak是获胜的算法,在2015年被标准化为 FIPS(联邦信息处理标准)202。

然而,在以太坊开发期间,NIST标准化工作正在完成。在标准过程完成后,NIST调整了Keccak的一些参数,据称可以提高效率。这与英雄告密者爱德华斯诺登透露的文件暗示NIST可能受到国家安全局的不当影响同时发生,故意削弱Dual_EC_DRBG随机数生成器标准,有效地在标准随机数生成器中放置一个后门。这场争论的结果是对所提议修改的反对以及SHA-3标准化的严重拖延。当时,以太坊基金会决定实施最初的Keccak算法。

Warning

虽然你可能在Ethereum文档和代码中看到“SHA3”,但很多(如果不是全部)这些实例实际上是指Keccak-256,而不是最终确定的FIPS-202 SHA-3标准。实现差异很小,与填充参数有关,但它们的重要性在于Keccak-256在给定相同输入的情况下产生与FIPS-202 SHA-3不同的哈希输出。

由于Ethereum中使用的哈希函数(Keccak-256)与最终标准(FIP-202 SHA-3)之间的差异造成了混淆,因此正在努力将代码中所有的 sha3 的所有实例,操作码和库重新命名为 keccak256。详情请参阅ethereum/EIPs#59

我正在使用哪个哈希函数?

如何判断你使用的软件库是FIPS-202 SHA-3还是Keccak-256(如果两者都可能被称为“SHA3”)?

一个简单的方法是使用_test vector_,一个给定输入的预期输出。最常用于哈希函数的测试是_empty input_。如果你使用空字符串作为输入运行哈希函数,你应该看到以下结果:

Testing whether the SHA3 library you are using is Keccak-256 of FIP-202 SHA-3

Keccak256("") =

c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470

SHA3("") =

a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a

因此,无论调用什么函数,都可以通过运行上面的简单测试来测试它是否是原始的Keccak-256或最终的NIST标准FIPS-202 SHA-3。请记住,以太坊使用Keccak-256,尽管它在代码中通常被称为SHA-3。

接下来,让我们来看一下Ethereum中Keccak-256的第一个应用,即从公钥生成以太坊地址。

以太坊地址

以太坊地址是 唯一标识符 unique identifiers,它们是使用单向哈希函数(Keccak-256)从公钥或合约派生的。

在我们之前的例子中,我们从一个私钥开始,并使用椭圆曲线乘法来派生一个公钥:

Private Key k:

k = f8f8a2f43c8376ccb0871305060d7b27b0554d2cc72bccf41b2705608452f315

Public Key K (X and Y coordinates concatenated and shown as hex):

K = 6e145ccef1033dea239875dd00dfb4fee6e3348b84985c92f103444683bae07b83b5c38e5e2b0c8529d7fa3f64d46daa1ece2d9ac14cab9477d042c84c32ccd0

Warning

值得注意的是,在计算地址时,公钥没有用前缀(十六进制)04格式化。

我们使用Keccak-256来计算这个公钥的_hash_:

Keccak256(K) = 2a5bc342ed616b5ba5732269001d3f1ef827552ae1114027bd3ecf1f086ba0f9

然后我们只保留最后的20个字节(大端序中的最低有效字节),这是我们的以太坊地址:

001d3f1ef827552ae1114027bd3ecf1f086ba0f9

大多数情况下,你会看到带有前缀“0x”的以太坊地址,表明它是十六进制编码,如下所示:

0x001d3f1ef827552ae1114027bd3ecf1f086ba0f9

以太坊地址格式

以太坊地址是十六进制数字,从公钥的Keccak-256哈希的最后20个字节导出的标识符。

与在所有客户端的用户界面中编码的比特币地址不同,它们包含内置校验和来防止输入错误的地址,以太坊地址以原始十六进制形式呈现,没有任何校验和。

该决定背后的基本原理是,以太坊地址最终会隐藏在系统高层的抽象(如名称服务)之后,并且必要时应在较高层添加校验和。

回想起来,这种设计选择导致了一些问题,包括由于输入错误地址和输入验证错误而导致的资金损失。以太坊名称服务的开发速度低于最初的预期,诸如ICAP之类的替代编码被钱包开发商采用得非常缓慢。

互换客户端地址协议 Inter Exchange Client Address Protocol (ICAP)

_互换客户端地址协议(ICAP)_是一种部分与国际银行帐号(IBAN)编码兼容的以太坊地址编码,为以太坊地址提供多功能,校验和互操作编码。ICAP地址可以编码以太坊地址或通过以太坊名称注册表注册的常用名称。

阅读以太坊Wiki上的ICAP:https://github.com/ethereum/wiki/wiki/ICAP:-Inter-exchange-Client-Address-Protocol

IBAN是识别银行账号的国际标准,主要用于电汇。它在欧洲单一欧元支付区(SEPA)及其以后被广泛采用。IBAN是一项集中和严格监管的服务。ICAP是以太坊地址的分散但兼容的实现。

一个IBAN由含国家代码,校验和和银行账户标识符(特定国家)的34个字母数字字符(不区分大小写)组成。

ICAP使用相同的结构,通过引入代表“Ethereum”的非标准国家代码“XE”,后面跟着两个字符的校验和以及3个可能的账户标识符变体:

Direct

最多30个字母数字字符big-endian base-36整数,表示以太坊地址的最低有效位。由于此编码适合小于155位,因此它仅适用于以一个或多个零字节开头的以太坊地址。就字段长度和校验和而言,它的优点是它与IBAN兼容。示例:XE60HAMICDXSV5QXVJA7TJW47Q9CHWKJD(33个字符长)

Baasic

与“Direct”编码相同,只是长度为31个字符。这使它可以编码任何以太坊地址,但使其与IBAN字段验证不兼容。示例:XE18CHDJBPLTBCJ03FE9O2NS0BPOJVQCU2P(35个字符长)

Indrect

编码通过名称注册表提供程序解析为以太坊地址的标识符。使用由_asset identifier_(例如ETH),名称服务(例如XREG)和9个字符的名称(例如KITTYCATS)组成的16个字母数字字符,这是一个人类可读的名称。示例:XE## ETHXREGKITTYCATS(20个字符长),其中“##”应由两个计算校验和字符替换。

我们可以使用 helpeth 命令行工具来创建ICAP地址。让我们尝试使用我们的示例私钥(前缀为0x并作为参数传递给helpeth):

$ helpeth keyDetails -p 0xf8f8a2f43c8376ccb0871305060d7b27b0554d2cc72bccf41b2705608452f315

Address: 0x001d3f1ef827552ae1114027bd3ecf1f086ba0f9

ICAP: XE60 HAMI CDXS V5QX VJA7 TJW4 7Q9C HWKJ D

Public key: 0x6e145ccef1033dea239875dd00dfb4fee6e3348b84985c92f103444683bae07b83b5c38e5e2b0c8529d7fa3f64d46daa1ece2d9ac14cab9477d042c84c32ccd0

helpeth 命令为我们构建了一个十六进制以太坊地址以及一个ICAP地址。我们示例密钥的ICAP地址是:

XE60HAMICDXSV5QXVJA7TJW47Q9CHWKJD

由于我们的示例以太坊地址恰好以零字节开始,因此可以使用IBAN格式中有效的“Direct”ICAP编码方法进行编码。因为它是33个字符长。

如果我们的地址不是从零开始,那么它将被编码为“Basic”编码,这将是35个字符长并且作为IBAN格式无效。

Tip

以零字节开始的任何以太坊地址的概率是1/256。为了生成这样一个类型,在我们找到一个作为IBAN兼容的“Direct”编码之前,它将平均用256个不同的随机私钥进行256次尝试ICAP地址。

不幸的是,现在,只有几个钱包支持ICAP。

使用大写校验和的十六进制编码 (EIP-55)

由于ICAP或名称服务部署缓慢,因此提出了一个新的标准,以太坊改进建议55(EIP-55)。你可以阅读详细信息:

https://github.com/Ethereum/EIPs/blob/master/EIPS/eip-55.md

通过修改十六进制地址的大小写,EIP-55为以太坊地址提供了向后兼容的校验和。这个想法是,以太坊地址不区分大小写,所有钱包都应该接受以大写字母或小写字母表示的以太坊地址,在解释上没有任何区别。

通过修改地址中字母字符的大小写,我们可以传达一个校验和,可以用来保护地址完整性,防止输入或读取错误。不支持EIP-55校验和的钱包简单地忽略地址包含混合大写的事实。但那些支持它的人可以验证它并以99.986%的准确度检测错误。

混合大小写编码很微妙,最初你可能不会注意到它。我们的示例地址是:

0x001d3f1ef827552ae1114027bd3ecf1f086ba0f9

使用 EIP-55 混合大小写校验和,它变为:

0x001d3F1ef827552Ae1114027BD3ECF1f086bA0F9

你能看出区别吗?一些来自十六进制编码字母表的字母(AF)字符现在是大写字母,而另一些则是小写字母。除非你仔细观察,否则你甚至可能没有注意到其中的差异。

EIP-55实施起来相当简单。我们采用小写十六进制地址的Keccak-256哈希。这个哈希作为地址的数字指纹,给我们一个方便的校验和。输入(地址)中的任何小改动都会导致哈希结果(校验和)发生很大变化,从而使我们能够有效地检测错误。然后我们的地址的哈希被编码为地址本身的大写字母。让我们一步步分解它:

  1. 计算小写地址的哈希,不带 0x 前缀::

Keccak256("001d3f1ef827552ae1114027bd3ecf1f086ba0f9")

23a69c1653e4ebbb619b0b2cb8a9bad49892a8b9695d9a19d8f673ca991deae1

  1. 如果哈希的相应十六进制数字大于或等于 0x8,则将每个字母地址字符大写。如果我们排列地址和哈希,这将更容易显示:

Address: 001d3f1ef827552ae1114027bd3ecf1f086ba0f9

Hash : 23a69c1653e4ebbb619b0b2cb8a9bad49892a8b9...

我们的地址在第四个位置包含一个字母 d。哈希的第四个字符是 6,小于+8+。所以,我们保持 d 小写。我们地址中的下一个字母字符是 f,位于第六位。十六进制哈希的第六个字符是 c,它大于+8 。因此,我们在地址中大写 +F,等等。正如你所看到的,我们只使用哈希的前20个字节(40个十六进制字符)作为校验和,因为我们只有20个字节(40个十六进制字符)能正确地大写。

检查自己产生的混合大写地址,看看你是否可以知道在地址哈希中哪些字符被大写和它们对应的字符:

Address: 001d3F1ef827552Ae1114027BD3ECF1f086bA0F9

Hash : 23a69c1653e4ebbb619b0b2cb8a9bad49892a8b9...

在EIP-55编码地址中检测错误

现在,我们来看看EIP-55地址如何帮助我们发现错误。假设我们已经打印出ETHER-E编码的以太坊地址:

0x001d3F1ef827552Ae1114027BD3ECF1f086bA0F9

现在,让我们在阅读该地址时犯一个基本错误。最后一个字符之前的字符是大写字母“F”。对于这个例子,我们假设我们误解为大写“E”。我们在钱包中输入(不正确的地址):

0x001d3F1ef827552Ae1114027BD3ECF1f086bA0E9

幸运的是,我们的钱包符合EIP-55标准!它注意到混合大写字母并试图验证地址。它将其转换为小写,并计算校验和哈希值:

Keccak256("001d3f1ef827552ae1114027bd3ecf1f086ba0e9")

5429b5d9460122fb4b11af9cb88b7bb76d8928862e0a57d46dd18dd8e08a6927

如你所见,即使地址只改变了一个字符(事实上,“e”和“f”只相隔1位),地址的哈希值已经根本改变了。这是哈希函数的特性,使它们对校验和非常有用!

现在,让我们排列这两个并检查大小写:

001d3F1ef827552Ae1114027BD3ECF1f086bA0E9

5429b5d9460122fb4b11af9cb88b7bb76d892886...

这都是错的!几个字母字符不正确地大写。请记住,大写是_正确的_校验和的编码。

我们输入的地址的大小写与刚刚计算的校验和不匹配,这意味着地址中的内容发生了变化,并且引入了错误。

おすすめ

転載: blog.csdn.net/qq_27246521/article/details/128583055