Block hashing algorithm

提供: tezos-wiki
移動先: 案内検索

Bitcoinマイニングでは、hashcash実証関数を使用します。ハッシュキャッシュアルゴリズムには、サービスストリング、ナンス、およびカウンターというパラメーターが必要です。ビット列では、サービス文字列はブロックヘッダデータ構造で符号化され、バージョンフィールド、前のブロックのハッシュ、ブロック内のすべてのトランザクションのメルクルツリーのルートハッシュ、現在の時間、および難易度が含まれます。 Bitcoinは、コーンベーストランザクションの一部であるextraNonceフィールドにナンスを格納します。これは、Merkleツリーの最左端のノードとして格納されます(コインベースは、ブロック内の特別な最初のトランザクションです)。カウンタパラメータは32ビットで小さいため、ラップするたびにrepeatNonceフィールドを増やす(または変更して)作業を繰り返さないようにする必要があります。 ハッシュキャッシュアルゴリズムの基本は理解しやすいので、これについては hereで詳しく説明しています。 ビットコインをマイニングするとき、ハッシュキャッシュアルゴリズムはブロックヘッダーを繰り返しハッシュし、counter&extraNonceフィールドをインクリメントします。 extraNonceフィールドをインクリメントするには、コインベースのトランザクションが左端のリーフノードであるため、Merkleツリーを再計算する必要があります。ブロックは、作業中に時折更新されることもあります。

ブロックヘッダーには次のフィールドがあります。

フィールド 目的 いつ更新... サイズ(バイト)
バージョン ブロックバージョン番号 ソフトウェアをアップグレードし、新しいバージョンを指定する 4
hashPrevBlock 前のブロックヘッダーの256ビットのハッシュ 新しいブロックが来る 32
hashMerkleRoot ブロック内のすべてのトランザクションに基づく256ビットのハッシュ 取引が受け入れられる 32
時間 現在のタイムスタンプ(1970-01-01T00:UTCからの秒数) 数秒ごと 4
ビット 現在のターゲットをコンパクト形式で [難しさ]を調整しました 4
ノンス 32ビット数(0から始まる) ハッシュが試行されます(増分) 4

ブロックの本体にはトランザクションが含まれています。これらは、Merkleルートを介して間接的にのみハッシュされます。トランザクションは直接ハッシングされないので、1つのトランザクションでブロックをハッシュすることは、10,000のトランザクションでブロックをハッシュすることとまったく同じ努力を要する。

コンパクトなフォーマットのターゲットは、3バイトの仮数を使用する特別な種類の浮動小数点符号化で、指数として先頭のバイト(5つの最下位ビットのみが使用されます)とその底は256です。 これらのフィールドのほとんどは、すべてのユーザーで同じになります。タイムスタンプに多少のばらつきがあるかもしれません。ナンスは通常異なるが、厳密に線形に増加する。 「Nonce」は0から始まり、各ハッシュに対してインクリメントされます。 Nonceがオーバーフローすると(頻繁に発生する)、生成トランザクションのextraNonce部分がインクリメントされ、Merkleルートが変更されます。

さらに、ブロック内の最初のトランザクションが "あなたの"独自のBitcoinアドレスの1つに "送信"されているため、2人が同じMerkleルートを持つことはほとんどありません。あなたのブロックは他のブロックとは異なるので、あなたは(ほとんど)異なるハッシュを生成することが保証されています。あなたが計算するすべてのハッシュは、ネットワークによって計算される他のすべてのハッシュと同じ勝利のチャンスを持ちます。 BitcoinではSHA256(SHA256(Block_Header))を使用していますが、バイトオーダーについては注意が必要です。

たとえば、このPythonコードは、2011年6月現在で最小のハッシュを持つブロックのハッシュを計算します[1]。ヘッダーは上記の6つのフィールドから作成され、16進表記でリトルエンディアン値として連結されます。

>>> import hashlib
>>> header_hex = "01000000" +
 "81cd02ab7e569e8bcd9317e2fe99f2de44d49ab2b8851ba4a308000000000000" +
 "e320b6c2fffc8d750423db8b1eb942ae710e951ed797f7affc8892b0f1fc122b" +
 "c7f5d74d" +
 "f2b9441a" +
 "42a14695"
>>> header_bin = header_hex.decode 'hex'
>>> hash = hashlib.sha256hashlib.sha256header_bin.digest())。digest()
>>> hash.encode 'hex_codec'
'1dbd981fe6985776b644b173a4d0385ddc1aa2a829688d1e0000000000000000'
>>> hash [:: - 1] .encode 'hex_codec'
'00000000000000001e8d6829a8a21adc5d38d0a473b144b6765798e61f98bd1d'

エンディアン[編集]

256ビットの数値であるハッシュは、ビッグエンディアンの16進定数として格納または印刷されるときに先行するゼロバイトがたくさんあることに注意してください。リトルエンディアンで保存または印刷すると、末尾にゼロバイトがあります。たとえば、文字列として解釈され、文字列アドレスの最下位(または先頭)が最下位バイトを保持する場合、リトルエンディアンです。

blockexplorerの出力は、ハッシュ値をビッグエンディアン数で表示します。数字の表記は通常です(先頭の数字は左から右へ読む最上位の数字です)。

別の例として、hereは、最適化、スレッド化、またはエラーチェックを行わずにプレーンCのバージョンです。

以下は、最適化のないプレーンなPHPの同じ例です。

<?
  //This reverses and then swaps every other char
  function SwapOrder($in){
      $Split = str_split(strrev($in));
      $x='';
      for ($i = 0; $i < count($Split); $i+=2) {
          $x .= $Split[$i+1].$Split[$i];
      } 
      return $x;
  }
  
  //makes the littleEndian
  function littleEndian($value){
      return implode (unpack('H*',pack("V*",$value)));
  }
  
  $version = littleEndian(1);
  $prevBlockHash = SwapOrder('00000000000008a3a41b85b8b29ad444def299fee21793cd8b9e567eab02cd81');
  $rootHash = SwapOrder('2b12fcf1b09288fcaff797d71e950e71ae42b91e8bdb2304758dfcffc2b620e3');
  $time = littleEndian(1305998791);
  $bits = littleEndian(440711666); 
  $nonce = littleEndian(2504433986); 
  
  //concat it all
  $header_hex = $version . $prevBlockHash . $rootHash . $time . $bits . $nonce;
  
  //convert from hex to binary 
  $header_bin  = hex2bin($header_hex);
  //hash it then convert from hex to binary 
  $pass1 = hex2bin(  hash('sha256', $header_bin )  );
  //Hash it for the seconded time
  $pass2 = hash('sha256', $pass1);
  //fix the order
  $FinalHash = SwapOrder($pass2);
  
  echo   $FinalHash;
?>