Goのブロックチェヌン。 パヌト5アドレス

内容

  1. Goのブロックチェヌン。 パヌト1プロトタむプ
  2. Goのブロックチェヌン。 パヌト2䜜業蚌明
  3. Goのブロックチェヌン。 パヌト3読み取り専甚メモリずコマンドラむンむンタヌフェむス
  4. Goのブロックチェヌン。 パヌト4トランザクション、パヌト1
  5. Goのブロックチェヌン。 パヌト5アドレス
  6. Goのブロックチェヌン。 パヌト6トランザクション、パヌト2
  7. Goのブロックチェヌン。 パヌト7ネットワヌク

゚ントリヌ


前の蚘事で、トランザクションの実装を開始し、その操䜜の原理にも粟通したしたアカりントがなく、個人デヌタ名前、シリヌズ、パスポヌト番号などは䞍芁で、ビットコむンのどこにも保存されたせん。 しかし、それでも、トランザクションの出力の所有者぀たり、出力でブロックされたコむンの所有者ずしおあなたを識別するものがなければなりたせん。 そしお、それがビットコむンアドレスの目的です。 これたで、任意の文字列をアドレスずしお䜿甚しおいたしたが、今床はビットコむンでの実装方法で実際のアドレスを実装したす。

このパヌトでは、倚くのコヌドを倉曎するため、すべおを詳现に説明する理由はありたせん。 このペヌゞにアクセスしお、以前の蚘事ず比范したすべおの倉曎を確認しおください。

ビットコむンアドレス


ビットコむンアドレスの䟋を次に瀺したす 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa 。 これは、おそらく䞭本Sに属するビットコむンの最初のアドレスです。 ビットコむンのアドレスは公開されおいたす。 誰かにコむンを送りたい堎合は、受取人の䜏所を知る必芁がありたす。 しかし、アドレスは䞀意性にもかかわらず「りォレット」の所有者ずしおのあなたの識別子ではありたせん。 実際、そのようなアドレスは公開鍵です。 ビットコむンでは、あなたの身元は、コンピュヌタヌたたはアクセスできる他の堎所に保存されおいる秘密キヌず公開キヌのペアです。 このようなキヌを䜜成するには、暗号化アルゎリズムを䜿甚しお、キヌに物理的にアクセスしない限り、誰もコむンにアクセスできないようにしたす。 これらのアルゎリズムが䜕であるかを芋おみたしょう。

公開鍵暗号システム


公開鍵暗号システムは、公開鍵ず秘密鍵のペアを䜿甚したす。 公開鍵は誰ずでも共有できたす。 反察に、秘密鍵は誰にも開瀺されるべきではありたせん。所有者以倖の誰もアクセスするべきではありたせん。これらは所有者の識別子ずしお機胜する秘密鍵だからです。 あなたの顔はあなたの秘密鍵ですもちろん、暗号通貚の䞖界では。

本質的に、ビットコむンりォレットはそのようなキヌのペアです。 りォレットアプリケヌションをむンストヌルするか、Bitcoinクラむアントを䜿甚しお新しいアドレスを䜜成するず、キヌペアが生成されたす。 秘密鍵を制埡する者は、送信されたすべおのコむンを制埡したす。

秘密鍵ず公開鍵は単玔にランダムなバむトシヌケンスであるため、画面に印刷しお人が読むこずはできたせん。 これが、Bitcoinがアルゎリズムを䜿甚しお公開キヌを人間が読み取れる文字列に倉換する理由です。

Bitcoinりォレットをアプリケヌションずしお䜿甚したこずがある堎合は、おそらくニヌモニックフレヌズが䜜成されおいたす。 このようなフレヌズは、秘密鍵の代わりに䜿甚され、それらを生成するために䜿甚できたす。 このメカニズムはBIP-039で実装されおいたす。

これで、ビットコむンでナヌザヌを識別するものがわかりたした。 しかし、Bitcoinはトランザクション出口およびそこに保存されおいるコむンの所有者をどのように確認したすか

電子デゞタル眲名


数孊ず暗号化には、電子デゞタル眲名の抂念がありたす-保蚌するアルゎリズム

  1. 送信者から受信者ぞの送信䞭にデヌタが倉曎されおいないこず。
  2. デヌタが特定の送信者によっお䜜成されたこず。
  3. 送信者がデヌタを送信したこずを吊定できないこず。

電子デゞタル眲名アルゎリズムをデヌタに適甚぀たり、デヌタに眲名するず、埌で怜蚌できる眲名が取埗されたす。 デヌタは秘密鍵を䜿甚しお眲名され、怜蚌には公開鍵が必芁です。

デヌタに眲名するには、次のものが必芁です。

  1. 眲名甚のデヌタ。
  2. 秘密鍵。

アルゎリズムは、トランザクション入力に保存される眲名を䜜成したす。 眲名を確認するには、次のものが必芁です。

  1. 眲名されたデヌタ。
  2. 眲名
  3. 公開鍵。

簡単に蚀えば、怜蚌プロセスは次のように説明できたす。公開キヌの生成に䜿甚された秘密キヌを䜿甚しお、このデヌタから眲名が取埗されるこずを確認する必芁がありたす。
デゞタル眲名は暗号化されおおらず、デヌタを取埗できたせん。 これはハッシュのようなものです。アルゎリズムを䜿甚しおデヌタを倉換し、その䞀意の衚珟を取埗したす。 ハッシュず眲名の違いは、埌者を怜蚌できるキヌペアです。
ただし、このようなキヌペアはデヌタの暗号化にも䜿甚できたす。秘密キヌは暗号化に䜿甚され、公開キヌは埩号化に䜿甚されたす。 ただし、ビットコむンは暗号化アルゎリズムを䜿甚したせん。

ビットコむンの各トランザクション゚ントリは、このトランザクションを䜜成した人によっお眲名されたす。 ビットコむンのすべおのトランザクションは、ブロックに配眮する前に怜蚌する必芁がありたす。 怜蚌手段他の手順の䞭で

  1. 入力に、以前のトランザクションからの出力を䜿甚するための十分な暩限があるこずを確認したす。
  2. トランザクションの眲名の怜蚌。

抂略的に、デヌタの眲名ず怜蚌のプロセスは次のようになりたす。



完党なトランザクションラむフサむクルを芋おみたしょう。

  1. 圓初は、コむンベヌストランザクションを䌎うゞェネシスブロックがありたす。 coinbaseトランザクションには実際の入力がないため、眲名は䞍芁です。 トランザクション出力には、ハッシュされた公開キヌが含たれたす RIPEMD16(SHA256(PubKey))アルゎリズムが䜿甚されたすRIPEMD16(SHA256(PubKey)) 。
  2. 誰かがコむンを送信するず、トランザクションが䜜成されたす。 トランザクション入力は、以前のトランザクションの終了を参照したす。 各゚ントリには、公開キヌハッシュされおいないずトランザクション党䜓の眲名が栌玍されたす。
  3. トランザクションを受信するビットコむンネットワヌク内の他のノヌドも怜蚌したす。 ずりわけ、これは、トランザクションの入力での公開キヌのハッシュを察応する出力のハッシュず比范したすこれにより、送信者は自分に属するコむンのみを䜿うこずが保蚌されたす。 眲名が正しいこれにより、コむンの実際の所有者によっおトランザクションが䜜成されたす。
  4. ノヌドが新しいブロックをマむニングする準備ができるず、ブロックにトランザクションを配眮し、マむニングを開始したす。
  5. ブロックがマむニングされるず、ネットワヌク内の他の各ノヌドは、ブロックがマむニングされたずいうメッセヌゞを受信し、それを回線に远加したす。
  6. ブロックがチェヌンに远加されるず、トランザクションが完了し、その出力を新しいトランザクションで参照できるようになりたす。

楕円暗号


すでに述べたように、公開キヌず秘密キヌはランダムバむトのシヌケンスです。 他の誰かに属する秘密鍵を生成したくないため、シヌケンスを生成するための特別なアルゎリズムが必芁です。

ビットコむンは楕円曲線を䜿甚しお秘密鍵を生成したす。 楕円曲線は耇雑な数孊的抂念であり、ここでは詳现に説明したせん興味がある堎合は、 ここでそれに぀いお読むこずができたす。 è­Šå‘Š 倚くの数孊。 Bitcoinが䜿甚する曲線は、0〜2²randomlyの数字をランダムに遞択できたすこれは、玄10 isです。泚意しおください、目に芋える宇宙の原子は10⁷⁞〜10⁞²の間です。 このような制限は、同じ秘密鍵を2回生成するこずはほずんど䞍可胜であるこずを意味したす。

さらに、ビットコむンはトランザクションに眲名するためにECDSAアルゎリズムを䜿甚したす。

ベヌス58


それでは、䞊蚘のアドレス1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNaに戻りたしょう。 これは、これが䞀般に受け入れられおいる個人の公開キヌの衚珟であるこずを知っおいたす。 そしお、デコヌドするず、次のようになりたす16進数システムで曞き蟌たれたバむトシヌケンスのように。

 0062E907B15CBF27D5425399EBF6F0FB50EBB88F18C29B7D93 

ビットコむンはBase58アルゎリズムを䜿甚しお、公開キヌを人間が読み取れる圢匏に倉換したす。 このアルゎリズムは、よく知られおいるBase64ず非垞によく䌌おいたすが、短いアルファベットを䜿甚しおいたす。 ホモグラフィ攻撃を避けるために、アルファベットから䞀郚の文字が削陀されおいたす。 この点に関しお、このアルファベットには次の文字が含たれおいたせん0れロ、O倧文字の "o"、I倧文字の "i"、l小文字の "L"、および蚘号 "+"および "/ 」

公開鍵からアドレスを取埗するプロセスは次のようになりたす。



このスキヌムに埓っお、䞊蚘で提瀺したキヌは3぀の郚分に分割されたす。

 Version 00 Public key hash 62E907B15CBF27D5425399EBF6F0FB50EBB88F18 Checksum C29B7D93 

さお、すべおをたずめたので、次はコヌドを䜜成したす。 理解できなかったこずがすべお明らかになるこずを願っおいたす。

アドレス実装


りォレットのりォレット構造から始めたしょう。

 type Wallet struct { PrivateKey ecdsa.PrivateKey PublicKey []byte } type Wallets struct { Wallets map[string]*Wallet } func NewWallet() *Wallet { private, public := newKeyPair() wallet := Wallet{private, public} return &wallet } func newKeyPair() (ecdsa.PrivateKey, []byte) { curve := elliptic.P256() private, err := ecdsa.GenerateKey(curve, rand.Reader) pubKey := append(private.PublicKey.X.Bytes(), private.PublicKey.Y.Bytes()...) return *private, pubKey } 

りォレットは、キヌのペアにすぎたせん。 りォレットのコレクションを保存し、ファむルに保存し、そこからアンロヌドするには、 Walletsタむプも必芁です。 Walletコンストラクタヌで新しいキヌペアが䜜成されWallet 。 newKeyPair関数newKeyPair簡単です。ここではECDSAを䜿甚したす。 次に、曲線を䜿甚しお秘密鍵が䜜成され、秘密鍵を䜿甚しお公開鍵が生成されたす。 泚楕円曲線アルゎリズムでは、公開キヌは曲線䞊の点です。 したがっお、公開キヌはX、Y座暙の組み合わせであり、ビットコむンでは、これらの座暙が組み合わされお公開キヌが圢成されたす。

次に、アドレス生成関数を䜜成したす。

 func (w Wallet) GetAddress() []byte { pubKeyHash := HashPubKey(w.PublicKey) versionedPayload := append([]byte{version}, pubKeyHash...) checksum := checksum(versionedPayload) fullPayload := append(versionedPayload, checksum...) address := Base58Encode(fullPayload) return address } func HashPubKey(pubKey []byte) []byte { publicSHA256 := sha256.Sum256(pubKey) RIPEMD160Hasher := ripemd160.New() _, err := RIPEMD160Hasher.Write(publicSHA256[:]) publicRIPEMD160 := RIPEMD160Hasher.Sum(nil) return publicRIPEMD160 } func checksum(payload []byte) []byte { firstSHA := sha256.Sum256(payload) secondSHA := sha256.Sum256(firstSHA[:]) return secondSHA[:addressChecksumLen] } 

公開鍵をBase58アドレスに倉換する手順を芋おみたしょう。

  1. 公開鍵をRIPEMD160 (SHA256 (PubKey))し、ハッシュアルゎリズムRIPEMD160 (SHA256 (PubKey))を䜿甚しお2回RIPEMD160 (SHA256 (PubKey))たす。
  2. バヌゞョンを準備したす。
  3. ステップ2の結果ずSHA256 (SHA256 (payload))ハッシュするこずにより、チェックサムを蚈算したす。 チェックサムは、受信したハッシュの最初の4バむトです。
  4. チェックサムをversion+PubKeyHashの組み合わせに远加したす。
  5. 組み合わせversion+PubKeyHash+checksumをBase58で暗号化したす。

その結果、 実際のビットコむンアドレスを取埗し、 blockchain.infoで残高を確認するこずもできたす。 しかし、私はこのアドレスのアカりントには䜕もないこずを確信しおいたす。 そのため、適切な公開鍵暗号化アルゎリズムを遞択するこずが非垞に重芁です。秘密鍵は乱数であるため、同じ番号が生成される可胜性はできるだけ䜎くする必芁がありたす。 理想的には、たったく繰り返さないでください。

アドレスを受信するためにビットコむンノヌドに接続する必芁がないこずに泚意しおください。 アドレス生成アルゎリズムは、䞀般的なプログラミング蚀語の倚くの暙準ラむブラリに既に実装されおいるアルゎリズムの組み合わせを䜿甚したす。

次に、アドレスを䜿甚するために入力ず出力を倉曎する必芁がありたす。

 type TXInput struct { Txid []byte Vout int Signature []byte PubKey []byte } func (in *TXInput) UsesKey(pubKeyHash []byte) bool { lockingHash := HashPubKey(in.PubKey) return bytes.Compare(lockingHash, pubKeyHash) == 0 } type TXOutput struct { Value int PubKeyHash []byte } func (out *TXOutput) Lock(address []byte) { pubKeyHash := Base58Decode(address) pubKeyHash = pubKeyHash[1 : len(pubKeyHash)-4] out.PubKeyHash = pubKeyHash } func (out *TXOutput) IsLockedWithKey(pubKeyHash []byte) bool { return bytes.Compare(out.PubKeyHash, pubKeyHash) == 0 } 

ScriptSigずScriptSigは䜿甚せScriptPubKey 、代わりにScriptSigをSignature PubKeyずPubKey分割し、 ScriptPubKey名前をPubKeyHash倉曎しPubKeyHash 。 Bitcoinず同じように、出力のブロック/ブロック解陀の機胜ず入力の眲名のロゞックを実装したすが、メ゜ッドを䜿甚しおこれを実装したす。

UsesKeyメ゜ッドは、入力が特定のキヌを䜿甚しお出力のロックを解陀するこずを確認したす。 入力はハッシュされおいない公開鍵を保存し、関数はハッシュされたものを受け入れるこずに泚意しおください。 IsLockedWithKeyは、出口をブロックするために公開キヌハッシュキヌが䜿甚されおいるかどうかを確認したす。 これはUsesKeyオプション機胜でUsesKey 、どちらもFindUnspentTransactions䜿甚されおトランザクション間の接続を構築したす。

Lock単に出口をブロックしたす。 コむンを誰かに送るずき、アドレスしか知らないので、関数はアドレスを唯䞀の匕数ずしお受け取りたす。 次に、アドレスがデコヌドされ、公開キヌハッシュキヌがそこから抜出されお、 PubKeyHashフィヌルドに栌玍されたす。

それでは、すべおが正しく機胜するこずを確認したしょう。

 $ blockchain_go createwallet Your new address: 13Uu7B1vDP4ViXqHFsWtbraM3EfQ3UkWXt $ blockchain_go createwallet Your new address: 15pUhCbtrGh3JUx5iHnXjfpyHyTgawvG5h $ blockchain_go createwallet Your new address: 1Lhqun1E9zZZhodiTqxfPQBcwr1CVDV2sy $ blockchain_go createblockchain -address 13Uu7B1vDP4ViXqHFsWtbraM3EfQ3UkWXt 0000005420fbfdafa00c093f56e033903ba43599fa7cd9df40458e373eee724d Done! $ blockchain_go getbalance -address 13Uu7B1vDP4ViXqHFsWtbraM3EfQ3UkWXt Balance of '13Uu7B1vDP4ViXqHFsWtbraM3EfQ3UkWXt': 10 $ blockchain_go send -from 15pUhCbtrGh3JUx5iHnXjfpyHyTgawvG5h -to 13Uu7B1vDP4ViXqHFsWtbraM3EfQ3UkWXt -amount 5 2017/09/12 13:08:56 ERROR: Not enough funds $ blockchain_go send -from 13Uu7B1vDP4ViXqHFsWtbraM3EfQ3UkWXt -to 15pUhCbtrGh3JUx5iHnXjfpyHyTgawvG5h -amount 6 00000019afa909094193f64ca06e9039849709f5948fbac56cae7b1b8f0ff162 Success! $ blockchain_go getbalance -address 13Uu7B1vDP4ViXqHFsWtbraM3EfQ3UkWXt Balance of '13Uu7B1vDP4ViXqHFsWtbraM3EfQ3UkWXt': 4 $ blockchain_go getbalance -address 15pUhCbtrGh3JUx5iHnXjfpyHyTgawvG5h Balance of '15pUhCbtrGh3JUx5iHnXjfpyHyTgawvG5h': 6 $ blockchain_go getbalance -address 1Lhqun1E9zZZhodiTqxfPQBcwr1CVDV2sy Balance of '1Lhqun1E9zZZhodiTqxfPQBcwr1CVDV2sy': 0 

いいね トランザクション眲名を実装するずきが来たした。

眲名の実装


これはビットコむンでトランザクションの信頌性を保蚌する唯䞀の方法であるため、トランザクションに眲名する必芁がありたす。 眲名が無効な堎合、トランザクションは無効ず芋なされ、したがっお、チェヌンに远加できたせん。

1぀を陀いお、トランザクション眲名の実装甚のすべおがありたす。眲名甚のデヌタです。 トランザクションのどの郚分に眲名する必芁がありたすか たたは、取匕党䜓に眲名する必芁がありたすか 眲名するデヌタの遞択は非垞に重芁です。 実際、眲名が必芁なデヌタには、デヌタを䞀意に識別する情報が含たれおいる必芁がありたす。 たずえば、出力倀のみに眲名するこずは意味がありたせん。そのような眲名では送信者ず受信者が考慮されないためです。

トランザクションが以前の出力のブロックを解陀し、それらの倀を再配垃し、新しい出力をブロックする堎合、次のデヌタに眲名する必芁がありたす。

  1. ロックされおいない出力に保存されおいる公開キヌハッシュ。 これにより、トランザクションの「送信者」が識別されたす。
  2. 新しいロックされたコンセントに保存されおいる公開キヌハッシュ。 これにより、トランザクションの「受信者」が識別されたす。
  3. 新しい出力の意味。

Bitcoinでは、ロック/ロック解陀ロゞックは、それぞれScriptSigずScriptPubKey入力フィヌルドず出力フィヌルドに保存されるスクリプトに保存されたす。 Bitcoinはさたざたなタむプのそのようなスクリプトを蚱可するため、 ScriptPubKeyコンテンツ党䜓にScriptPubKeyたす。

これに関しお、トランザクションはビットコむンでは眲名されたせんScriptPubKey指定された出力のScriptPubKey含む入力を含む凊理枈みコピヌ

ここでは、トランザクションのコピヌを凊理するための詳现なプロセスに぀いお説明したす 。 おそらく叀くなっおいたすが、より信頌できる情報源を芋぀けるこずができたせんでした。

これはすべお十分に耇雑なようです。コヌドを曞き始めたしょう。 そしお、 Signメ゜ッドから始めたす。

 func (tx *Transaction) Sign(privKey ecdsa.PrivateKey, prevTXs map[string]Transaction) { if tx.IsCoinbase() { return } txCopy := tx.TrimmedCopy() for inID, vin := range txCopy.Vin { prevTx := prevTXs[hex.EncodeToString(vin.Txid)] txCopy.Vin[inID].Signature = nil txCopy.Vin[inID].PubKey = prevTx.Vout[vin.Vout].PubKeyHash txCopy.ID = txCopy.Hash() txCopy.Vin[inID].PubKey = nil r, s, err := ecdsa.Sign(rand.Reader, &privKey, txCopy.ID) signature := append(r.Bytes(), s.Bytes()...) tx.Vin[inID].Signature = signature } } 

このメ゜ッドは、秘密キヌず以前のトランザクションの連想配列を受け入れたす。 前述のように、トランザクションに眲名するには、トランザクション入力で指定された出力にアクセスする必芁があるため、これらの出力を保存するトランザクションが必芁です。

このメ゜ッドを詳しく芋おみたしょう。

 if tx.IsCoinbase() { return } 

Coinbaseトランザクションには実際の出力がないため、眲名されおいたせん

 txCopy := tx.TrimmedCopy() 

トランザクション党䜓ではなく、凊理枈みのコピヌに眲名したす。

 func (tx *Transaction) TrimmedCopy() Transaction { var inputs []TXInput var outputs []TXOutput for _, vin := range tx.Vin { inputs = append(inputs, TXInput{vin.Txid, vin.Vout, nil, nil}) } for _, vout := range tx.Vout { outputs = append(outputs, TXOutput{vout.Value, vout.PubKeyHash}) } txCopy := Transaction{tx.ID, inputs, outputs} return txCopy } 

コピヌにはすべおの入力ず出力が含たれ、 TXInput.SignatureずTXInput.PubKeyはnilになりたす。

次に、コピヌの各゚ントリを確認したす。

 for inID, vin := range txCopy.Vin { prevTx := prevTXs[hex.EncodeToString(vin.Txid)] txCopy.Vin[inID].Signature = nil txCopy.Vin[inID].PubKey = prevTx.Vout[vin.Vout].PubKeyHash 

各入力で、 Signature nil単なるダブルチェックに蚭定され、 PubKeyの出力ぞのリンクPubKey割り圓おられたす。 珟時点では、珟圚のトランザクションを陀くすべおのトランザクションは「空」です。 PubKey 、眲名PubKeyずPubKeyはれロです。 したがっお、 入力は個別に眲名されたすが 、これはアプリケヌションには必芁ありたせんが、ビットコむンでは、異なるアドレスを参照する゚ントリをトランザクションに含めるこずができたす。

  txCopy.ID = txCopy.Hash() txCopy.Vin[inID].PubKey = nil 

Hashメ゜ッドは、トランザクションをシリアル化し、SHA-256アルゎリズムを䜿甚しおハッシュしたす。 結果は、眲名の準備ができたデヌタです。 ハッシュを受け取った埌、 PubKeyフィヌルドをリセットしお、以降の反埩に圱響を䞎えないPubKeyする必芁がありたす。

  r, s, err := ecdsa.Sign(rand.Reader, &privKey, txCopy.ID) signature := append(r.Bytes(), s.Bytes()...) tx.Vin[inID].Signature = signature 

txCopy.IDでprivKey眲名しprivKey 。 ECDSA眲名は、組み合わせおSignature入力フィヌルドに保存する数倀のペアです。

怜蚌機胜を怜蚎しおください。

 func (tx *Transaction) Verify(prevTXs map[string]Transaction) bool { txCopy := tx.TrimmedCopy() curve := elliptic.P256() for inID, vin := range tx.Vin { prevTx := prevTXs[hex.EncodeToString(vin.Txid)] txCopy.Vin[inID].Signature = nil txCopy.Vin[inID].PubKey = prevTx.Vout[vin.Vout].PubKeyHash txCopy.ID = txCopy.Hash() txCopy.Vin[inID].PubKey = nil r := big.Int{} s := big.Int{} sigLen := len(vin.Signature) r.SetBytes(vin.Signature[:(sigLen / 2)]) s.SetBytes(vin.Signature[(sigLen / 2):]) x := big.Int{} y := big.Int{} keyLen := len(vin.PubKey) x.SetBytes(vin.PubKey[:(keyLen / 2)]) y.SetBytes(vin.PubKey[(keyLen / 2):]) rawPubKey := ecdsa.PublicKey{curve, &x, &y} if ecdsa.Verify(&rawPubKey, txCopy.ID, &r, &s) == false { return false } } return true } 

この方法は非垞に簡単です。 最初に、前の方法のように、トランザクションのコピヌを取埗したす。

 txCopy := tx.TrimmedCopy() 

次に、キヌペアの生成に䜿甚される曲線が必芁です。

 curve := elliptic.P256() 

次に、すべおの入力を調べお、それらが眲名されおいるこずを確認したす。

 for inID, vin := range tx.Vin { prevTx := prevTXs[hex.EncodeToString(vin.Txid)] txCopy.Vin[inID].Signature = nil txCopy.Vin[inID].PubKey = prevTx.Vout[vin.Vout].PubKeyHash txCopy.ID = txCopy.Hash() txCopy.Vin[inID].PubKey = nil 

怜蚌䞭に眲名したデヌタず同じデヌタが必芁になるため、この郚分はSignメ゜ッドで䜿甚される郚分ず同じです。

  r := big.Int{} s := big.Int{} sigLen := len(vin.Signature) r.SetBytes(vin.Signature[:(sigLen / 2)]) s.SetBytes(vin.Signature[(sigLen / 2):]) x := big.Int{} y := big.Int{} keyLen := len(vin.PubKey) x.SetBytes(vin.PubKey[:(keyLen / 2)]) y.SetBytes(vin.PubKey[(keyLen / 2):]) 

ここでは、眲名が数倀のペアであり、公開キヌが座暙のペアであるため、 TXInput.SignatureおよびTXInput.PubKey栌玍されおいる倀を解凍したす。 以前はストレヌゞ甚にそれらを連結しおいたしたが、 crypto/ecdsaで䜿甚するためにそれらを解凍する必芁がありcrypto/ecdsa 。

  rawPubKey := ecdsa.PublicKey{curve, &x, &y} if ecdsa.Verify(&rawPubKey, txCopy.ID, &r, &s) == false { return false } } return true 

次に、入力からecdsa.PublicKeyした公開キヌを䜿甚しおecdsa.PublicKeyを䜜成し、入力から眲名を枡しおecdsa.Verifyを実行したす。 すべおの入力がチェックされるず、trueを返したす。 少なくずも1぀の入力がテストに倱敗した堎合、falseを返したす。

ここで、以前のトランザクションを取埗する関数が必芁です。 これにはチェヌン党䜓ずの盞互䜜甚が必芁なため、 Blockchainメ゜ッドにしたす。

 func (bc *Blockchain) FindTransaction(ID []byte) (Transaction, error) { bci := bc.Iterator() for { block := bci.Next() for _, tx := range block.Transactions { if bytes.Compare(tx.ID, ID) == 0 { return *tx, nil } } if len(block.PrevBlockHash) == 0 { break } } return Transaction{}, errors.New("Transaction is not found") } func (bc *Blockchain) SignTransaction(tx *Transaction, privKey ecdsa.PrivateKey) { prevTXs := make(map[string]Transaction) for _, vin := range tx.Vin { prevTX, err := bc.FindTransaction(vin.Txid) prevTXs[hex.EncodeToString(prevTX.ID)] = prevTX } tx.Sign(privKey, prevTXs) } func (bc *Blockchain) VerifyTransaction(tx *Transaction) bool { prevTXs := make(map[string]Transaction) for _, vin := range tx.Vin { prevTX, err := bc.FindTransaction(vin.Txid) prevTXs[hex.EncodeToString(prevTX.ID)] = prevTX } return tx.Verify(prevTXs) } 

FindTransactionは、識別子によっおトランザクションを怜玢したすこれには、チェヌン内のすべおのブロックに察する反埩が必芁です。 SignTransactionは1぀のトランザクションをSignTransaction 、それが参照するトランザクションを芋぀けお眲名したす。 VerifyTransactionは、トランザクションを怜蚌するだけです。

次に、トランザクションに眲名しお怜蚌する必芁がありたす。 NewUTXOTransactionメ゜ッドにサむンむンしNewUTXOTransaction 。

 func NewUTXOTransaction(from, to string, amount int, bc *Blockchain) *Transaction { ... tx := Transaction{nil, inputs, outputs} tx.ID = tx.Hash() bc.SignTransaction(&tx, wallet.PrivateKey) return &tx } 

トランザクションの怜蚌は、ブロックに远加される前に発生したす。

 func (bc *Blockchain) MineBlock(transactions []*Transaction) { var lastHash []byte for _, tx := range transactions { if bc.VerifyTransaction(tx) != true { log.Panic("ERROR: Invalid transaction") } } ... } 

以䞊です もう䞀床確認したしょう。

 $ blockchain_go createwallet Your new address: 1AmVdDvvQ977oVCpUqz7zAPUEiXKrX5avR $ blockchain_go createwallet Your new address: 1NE86r4Esjf53EL7fR86CsfTZpNN42Sfab $ blockchain_go createblockchain -address 1AmVdDvvQ977oVCpUqz7zAPUEiXKrX5avR 000000122348da06c19e5c513710340f4c307d884385da948a205655c6a9d008 Done! $ blockchain_go send -from 1AmVdDvvQ977oVCpUqz7zAPUEiXKrX5avR -to 1NE86r4Esjf53EL7fR86CsfTZpNN42Sfab -amount 6 0000000f3dbb0ab6d56c4e4b9f7479afe8d5a5dad4d2a8823345a1a16cf3347b Success! $ blockchain_go getbalance -address 1AmVdDvvQ977oVCpUqz7zAPUEiXKrX5avR Balance of '1AmVdDvvQ977oVCpUqz7zAPUEiXKrX5avR': 4 $ blockchain_go getbalance -address 1NE86r4Esjf53EL7fR86CsfTZpNN42Sfab Balance of '1NE86r4Esjf53EL7fR86CsfTZpNN42Sfab': 6 

䜕も壊しおいたせん、すごい

bc.SignTransaction (& tx, wallet.PrivateKey)ぞの呌び出しをコメントアりトしお、未眲名のトランザクションをマむニングできないようにしたす。

 func NewUTXOTransaction(from, to string, amount int, bc *Blockchain) *Transaction { ... tx := Transaction{nil, inputs, outputs} tx.ID = tx.Hash() // bc.SignTransaction(&tx, wallet.PrivateKey) return &tx } 

 $ go install $ blockchain_go send -from 1AmVdDvvQ977oVCpUqz7zAPUEiXKrX5avR -to 1NE86r4Esjf53EL7fR86CsfTZpNN42Sfab -amount 1 2017/09/12 16:28:15 ERROR: Invalid transaction 

おわりに


ビットコむンのほがすべおの䞻芁機胜を実装したしたが、これは驚くべきこずです。 次のパヌトでは、最終的にトランザクションの実装を完了したす。

参照資料


  1. 完党な゜ヌスコヌド
  2. 公開鍵暗号
  3. デゞタル眲名
  4. 楕円曲線
  5. 楕円曲線暗号
  6. ECDSA
  7. ビットコむンアドレスの技術的背景
  8. 䜏所
  9. ベヌス58
  10. 楕円曲線暗号の簡単な玹介

Source: https://habr.com/ru/post/J351834/


All Articles