サルでもわかる?ブロックチェーン復習

ブロックチェーンについて復習します
これを読めばサルでもわかるかも?

1786 views

アドレスが生成されるまで

アドレスって何?

「アドレス」は、仮想通貨を送る・受け取る際に利用するものや。
「仮想通貨を送る・受け取る」性質上、アドレスは多くの人が目にするわ。
ただ、個人と紐づいているプライバシーの高いものでもあるわ。
要するに

  • 公開性
  • 秘匿性

この二つを満たす必要があるわけやな

アドレスが生成されるまでの全体像

「アドレス」は「秘密鍵」から作られているわ。
「秘密鍵」から「アドレス」が作られるには下図手順を踏むんやで

[秘密鍵]

  • 秘密鍵が乱数として生成されるわ

[公開鍵]

  • 次に楕円曲線ちゅう暗号技術で公開鍵を生成するんや

[アドレス]

  • そこから2回ハッシュ化しBase58Checkでエンコード
  • アドレスを生成するんや

秘密鍵の生成

秘密鍵の本質は乱数や。乱数はランダムに生成される数や。
乱数が本当にランダムかは、非常に重要やで。規則性があると悪意のある第三者に秘密鍵が悪用されるわ。

秘密鍵を生成する

[入力]

import os
import binascii

#32バイトの乱数の生成
private_key = os.urandom(32)

print(private_key)
#バイナリデータを16進数に変換する(これはわかりやすくするためにやっている)
print(binascii.hexlify(private_key))

[出力]

b'V!-Z\xfb\x11\xb6\x9c\xc9\xc5s\\\x9a\xeeU\xf4\xa4\xfc8\x9b\x03\xbeD\xab\xf9eD\x93\xaa\x19&\x1a'
b'56212d5afb11b69cc9c5735c9aee55f4a4fc389b03be44abf9654493aa19261a'

公開鍵の生成

楕円曲線を利用してみよう

[入力]

import ecdsa
import os
import binascii

#秘密鍵生成
private_key = os.urandom(32)

#公開鍵の生成
public_key = ecdsa.SigningKey.from_string(private_key,curve=ecdsa.SECP256k1).verifying_key.to_string()

print(binascii.hexlify(private_key))
print(binascii.hexlify(public_key))

[出力]

#毎回異なる値が出力される
b'8ea97805a01622ed58d48e0618ede12bb78882570e1008ae0544a89fa76db8a0'
b'0f23ae30c79de5587395d0c66b7533e3648e08b5aab4e8fe87001a5470bdc035b68ef004efd8f2b342d28abf2219a3e9d3aec26e6d9f15aef5c1afb0e47ce906'

===細かい説明は今度するわ...===

公開鍵のフォーマット

  • 圧縮公開鍵
  • 非圧縮公開鍵

非圧縮公開鍵

非圧縮公開鍵は前節で導き出した公開鍵に「プレフィックス」として「04」を付加したもの。
「プレフィックス」とは、接頭辞のこと。特定の意味を持たせる

圧縮公開鍵

公開鍵「楕円曲線」で作られている。よって座標を求めることができる。
圧縮公開鍵の場合、座標Yの値によってプレフィックスを変更する。

  • 正:02
  • 負:03

公開鍵・圧縮公開鍵の生成

[入力]

import ecdsa
import os
import binascii

#秘密鍵生成
private_key = os.urandom(32)

#公開鍵の生成
public_key = ecdsa.SigningKey.from_string(private_key,curve=ecdsa.SECP256k1).verifying_key.to_string()

#Y座標を取得(32から取得。)
public_key_y = int.from_bytes(public_key[32:],"big")

#圧縮公開鍵を生成(32まで取得)
if public_key_y %2 == 0:
    public_key_compressed = b"\x02"+public_key[:32]
else:
    public_key_compressed = b"\x03"+public_key[:32]

#実行するたび値が変わる
print(binascii.hexlify(public_key))
print(binascii.hexlify(public_key_compressed))

[出力]

b'6b57dab2663217d95fb73a14a92b758cc087f84f099cca50fdcdaeb444985b6ed41bebfac760d8f3da6ffafd09a7ccd7d1f3872369152cea0402f08a0972895c'
b'026b57dab2663217d95fb73a14a92b758cc087f84f099cca50fdcdaeb444985b6e'

アドレスの生成

可読性を高める工夫

ここまで予測されないように秘密鍵を生成し、逆算不可な「公開鍵」を生成した。
ここからは、エンコードして可読性を高めて、誤読を防ぐ工夫をするんやで
具体的には「RIPEMD-160」で文字量を減らし「Base58Check」でエンコードする

Base58

「Base58」は人が見て間違えやすい文字を排除するエンコード方式や。
例えば、Oと0とかやな。ほかには以下の文字があげられるわ。

  • I
  • l
  • +
  • /

Base58Check

公開鍵からアドレスを生成する際はチェックサムを使用した「Base58Check」を用いるわ。
「チェックサム」ってのはデータが間違っていないか確認する手法や。


ここでのチェックサムは、公開鍵のハッシュ値とその先頭にバージョンバイトをつなげたものから
1. SHA-256で2回ハッシュ化する
2. その先頭4バイトを利用する

プロセスは以下の通りや。


バージョンバイトってのは、生成するアドレスがどのようなタイプのアドレスかを示す。
16進数の情報やで。
別名:Version Prefix とも呼ぶわ。
代表的なバージョンバイトは下の通りや

バージョンバイト 意味 エンコード後
0x00 公開鍵ハッシュ 1
0x05 スクリプトハッシュ 3
0x08 秘密鍵WIF形式 5
0x0488B21E BIP32拡張公開鍵 xpub

アドレスを生成する

公開鍵からアドレスを生成するプロセスは以下の通りやで

  1. 公開鍵をSHA-256でハッシュ値①にハッシュ化
  2. ハッシュ値①をRIPEMD-160でハッシュ値②に変換
  3. ハッシュ値②をBase58Checkエンコード

[入力]

import ecdsa
import os
import base58
import hashlib

#秘密鍵生成
private_key = os.urandom(32)

#公開鍵の生成
public_key = ecdsa.SigningKey.from_string(private_key,curve=ecdsa.SECP256k1).verifying_key.to_string()

#非圧縮公開鍵
prefix_and_pubkey = b"\x04"+ public_key

#hash160を作成
intermediate = hashlib.sha256(prefix_and_pubkey).digest()
ripemd160 = hashlib.new('ripemd160')
ripemd160.update(intermediate)
hash160 = ripemd160.digest()

#ハッシュ160 + バージョンプレフィックス
prefix_and_hash160 = b"\x00" + hash160

#hashlib.256を入れる
double_hash = hashlib.sha256(hashlib.sha256(prefix_and_hash160).digest()).digest()

#チェックサム
check_sum = double_hash[:4]

pre_address = prefix_and_hash160 + check_sum
#base58でエンコード
address = base58.b58encode(pre_address)
print(address)

[出力]

#実行する毎に変更する
b'1PwungCcLKepQCQZZB73hEc6PboB6GjFPr'

Page 6 of 9.

前のページ 次のページ



[添付ファイル]


お問い合わせ

プロフィール

owl

自己紹介

駆け出しエンジニア
だいたいweb系をかじってる
最近ちょとブロックチェーンに興味出てきた

サイト/ブログ

https://github.com/owl0109

ツイッター

@kijiken1