[Bitcoin] モジュロ演算

四則演算(加算、減算、乗算、除算)について閉じている有限体を作るために利用できる道具がモジュロ演算
モジュロ演算:1つの数を別の数で割った余りの数を求めること
(3 – 16) % 12 = 11
(12 + 843) % 60 = 15
(23 + 97) % 60 = 0

pythonのモジュロ演算

print(7 % 3)
print(-27 % 13) 

$ python3 app.py
1
12

有限体上の加算が閉じていることを確認する必要がある
F19 = {0, 1, 2…18}

F57

prime = 57
print((44+33)%prime)
print((9-29)%prime)
print((17+42+49)%prime)
print((52-30-38)%prime)

### 加算と減算

// 省略
	def __add__(self, other):
		if self.prime != other.prime:
			raise TypeError('Cannot add two numbers in different Fields')
		num = (self.num + other.num) % self.prime
		return self.__class__(num, self.prime)

	def __sub__(self, other):
		if self.prime != other.prime:
			raise TypeError('Cannot subtract two numbers in different Fields')
		num = (self.num - other.num) % self.prime
		return self.__class__(num, self.prime)		

a = FieldElement(7, 13)
b = FieldElement(12, 13)
c = FieldElement(6, 13)
print(a+b==c)

### 乗算とべき乗
べき乗は乗算を繰り返し

prime = 97
print(95*45*31 % prime)
print(17*13*19*44 % prime)
print(17**7 * 77**49 % prime)

乗算

	def __mul__(self, other):
		if self.prime != other.prime:
			raise TypeError('Cannot multiply two numbers in different Fields')
		num = (self.num * other.num) % self.prime
		return self.__class__(num, self.prime)

a = FieldElement(3, 13)
b = FieldElement(12, 13)
c = FieldElement(10, 13)
print(a*b==c)

べき乗

	def __pow__(self, exponent):
		num = (self.num ** exponent) % self.prime
		return self.__class__(num, self.prime)

a = FieldElement(3, 13)
b = FieldElement(1, 13)
print(a**3==b)
for prime in (7, 11, 17, 31):
	print([pow(i, prime-1, prime) for i in range(1, prime)])

### 有限体上の除算

prime = 31
print(3*pow(24, prime-2, prime) % prime)
print(pow(17, prime-4, prime))
print(pow(4, prime-5, prime)*11 % prime)
	def __truediv__(self, other):
		if self.prime != other.prime:
			raise TypeError('Cannot divide two numbers in different Fields')
		num = self.num * pow(other.num, self.prime - 2, self.prime) % self.prime
		return self.__class__(num, self.prime)

いきなり難しいな

[Blockchain] Bitcoinの学習開始

$ sudo apt install python3-virtualenv
$ virtualenv -p python3 .venv
$ .venv/vin/activate
$ . .venv/bin/activate
$ pip3 install -r requirements.txt

// vagrant上でjupyter notebookを起動する
$ jupyter notebook –no-browser –ip=0.0.0.0

ビットコインは相互に依存するコンポーネントが多数存在する
楕円曲線暗号(ECC)が基礎となる
L 署名アルゴリズム、検証アルゴリズム … トランザクションの仕組みの中心
  L シェノア署名、秘匿トランザクションなどの技術

### 有限体
有限の個数からなる集合と演算
集合が閉じている、加法単位元、乗法単位元、加法逆元、乗法逆元

### 有限集合
Fp = {0,1,2,…p-1}
体の位数は素数のべき乗となる

class FieldElement:

	def __init__(self, num, prime):
		if num >= prime or num < 0:
			error = 'Num {} not in field range 0 to {}'.format(
				num, prime - 1)
			raise ValueError(error)
		self.num = num
		self.prime = prime

	def __repr__(self):
		return 'FieldElement_{}({})'.format(self.prime, self.num)

	def __eq__(self, other):
		if other is None:
			return False
		return self.num == other.num and self.prime == other.prime

a = FieldElement(7, 13)
b = FieldElement(6, 13)
print(a==b)
print(a==a)

$ python3 app.py
False
True

DNSシードのanswer section

digでmainnetのdnsseed.bluematt.meを叩く。
2つ目の項目”59″はTTL。CNAMEはあだ名みたいなことで、dnsseed.bluematt.me = x1.dnsseed.bluematt.me
下のIPがアクティブノードの接続先。
こうやってみると、DNSシードのレスポンスはアクティブノードのIPのみってことになる。

dnsseed.bluematt.me.	3599	IN	CNAME	x1.dnsseed.bluematt.me.
x1.dnsseed.bluematt.me.	59	IN	A	193.111.156.2
x1.dnsseed.bluematt.me.	59	IN	A	40.115.137.28
x1.dnsseed.bluematt.me.	59	IN	A	199.188.207.22
x1.dnsseed.bluematt.me.	59	IN	A	51.154.60.34
x1.dnsseed.bluematt.me.	59	IN	A	185.233.186.20
x1.dnsseed.bluematt.me.	59	IN	A	84.59.243.22
x1.dnsseed.bluematt.me.	59	IN	A	151.228.87.150
x1.dnsseed.bluematt.me.	59	IN	A	125.236.215.133
x1.dnsseed.bluematt.me.	59	IN	A	91.204.149.5
x1.dnsseed.bluematt.me.	59	IN	A	182.239.237.53
x1.dnsseed.bluematt.me.	59	IN	A	159.138.87.18
x1.dnsseed.bluematt.me.	59	IN	A	94.68.239.149
x1.dnsseed.bluematt.me.	59	IN	A	96.31.1.212
x1.dnsseed.bluematt.me.	59	IN	A	185.83.110.53
x1.dnsseed.bluematt.me.	59	IN	A	193.58.196.212
x1.dnsseed.bluematt.me.	59	IN	A	203.132.95.10
x1.dnsseed.bluematt.me.	59	IN	A	92.65.24.209
x1.dnsseed.bluematt.me.	59	IN	A	80.111.142.213
x1.dnsseed.bluematt.me.	59	IN	A	88.212.44.33
x1.dnsseed.bluematt.me.	59	IN	A	93.175.204.121
x1.dnsseed.bluematt.me.	59	IN	A	193.112.93.235

mainnetの、dnsseed.bitcoin.dashjr.orgの方もみてみます。あれ、dnsseed.bluematt.meとdnsseed.bitcoin.dashjr.orgだと、登録されているアクティブノードのIPが異なりますね。

dnsseed.bitcoin.dashjr.org. 429	IN	A	67.80.165.100
dnsseed.bitcoin.dashjr.org. 429	IN	A	37.187.122.82
dnsseed.bitcoin.dashjr.org. 429	IN	A	90.187.75.113
dnsseed.bitcoin.dashjr.org. 429	IN	A	155.138.208.87
dnsseed.bitcoin.dashjr.org. 429	IN	A	84.255.244.61
dnsseed.bitcoin.dashjr.org. 429	IN	A	85.214.38.87
dnsseed.bitcoin.dashjr.org. 429	IN	A	95.179.221.214
dnsseed.bitcoin.dashjr.org. 429	IN	A	173.249.0.235
dnsseed.bitcoin.dashjr.org. 429	IN	A	185.107.83.55
dnsseed.bitcoin.dashjr.org. 429	IN	A	139.162.7.9
dnsseed.bitcoin.dashjr.org. 429	IN	A	178.63.40.164
dnsseed.bitcoin.dashjr.org. 429	IN	A	96.241.146.239
dnsseed.bitcoin.dashjr.org. 429	IN	A	73.93.12.65
dnsseed.bitcoin.dashjr.org. 429	IN	A	119.17.151.61
dnsseed.bitcoin.dashjr.org. 429	IN	A	34.244.231.62
dnsseed.bitcoin.dashjr.org. 429	IN	A	94.112.167.129
dnsseed.bitcoin.dashjr.org. 429	IN	A	155.138.235.87
dnsseed.bitcoin.dashjr.org. 429	IN	A	199.247.18.168
dnsseed.bitcoin.dashjr.org. 429	IN	A	45.16.103.141
dnsseed.bitcoin.dashjr.org. 429	IN	A	5.135.159.65
dnsseed.bitcoin.dashjr.org. 429	IN	A	89.47.217.222
dnsseed.bitcoin.dashjr.org. 429	IN	A	185.25.48.148
dnsseed.bitcoin.dashjr.org. 429	IN	A	35.209.163.61

bluemattの方のipをjsonファイルに書き換えてみます。

{
	"ip": ["193.111.156.2", "40.115.137.28", "199.188.207.22", "51.154.60.34", "185.233.186.20", "84.59.243.22", "151.228.87.150", "125.236.215.133", "91.204.149.5", "182.239.237.53"]
}

Bitcoin Coreはノード情報をディスク上のDBに保存って仕組みでしたね。
あれ、ディスクのDBってどういうこと?ubuntuだったら、postgresってこと?

P2Pネットワークの仕組みを作ろう

イメージとしては、DNSシードが複数のノードIPを持っていて、シードから取得すると、ノードにアクセスしてハンドシェイクって流れだ。

こんな感じ。

さて、これをどーやってコーディングしていきましょうか。。。

BIP, Open Asset Protocol

富士通の帳票ソフトウェアではありません。
Bitcoin Improvement Proposal
https://github.com/bitcoin/bips

ソフトフォークとハードフォークでプロセスが異なる

Open Asset Protocolは、仮想通貨以外のアセットを発行・取引する
https://github.com/OpenAssets/open-assets-protocol

bitcoin white paper
https://bitcoin.org/files/bitcoin-paper/bitcoin_jp.pdf

どうなってんだこれ。。

ノードとネットワーク

ビットコインのプロトコルに対応するノードはフルノードと呼ばれる全取引データを保持するノードとSPV(Simplified Payment Vertification)と呼ばれるブロックヘッダと自分に関連するデータのみを保持する軽量ノードがある
Bitcoin Coreはフルノード
ブロックのヘッダのみをダウンロードし、必要に応じてフルノードにトランザクションを要求するクライアントでSPVノードと呼ぶ

■ネットワークの発見
最初はDNSシードに問い合わせにいく
– seed.bitcoin.sipa.be
– denseed.bitcoin.dashjr.org
– eed.bitcoinstats.com
– seed.bitcoin.jonasschnelli.ch

DNSシードに問い合わせると、新しい接続を受け入れられるフルノードのIPアドレスが1つ以上返ってくる

vagrant@vagrant-ubuntu-trusty-64:~/bitcoin$ dig seed.bitcoin.sipa.be

; <<>> DiG 9.9.5-3ubuntu0.19-Ubuntu <<>> seed.bitcoin.sipa.be
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 34073 ;; flags: qr rd ra; QUERY: 1, ANSWER: 25, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 512 ;; QUESTION SECTION: ;seed.bitcoin.sipa.be. IN A ;; ANSWER SECTION: seed.bitcoin.sipa.be. 3599 IN A 104.248.20.174 seed.bitcoin.sipa.be. 3599 IN A 79.124.17.204 seed.bitcoin.sipa.be. 3599 IN A 5.135.186.15 seed.bitcoin.sipa.be. 3599 IN A 104.171.172.17 seed.bitcoin.sipa.be. 3599 IN A 94.130.207.23 seed.bitcoin.sipa.be. 3599 IN A 138.201.56.109 seed.bitcoin.sipa.be. 3599 IN A 73.255.112.134 seed.bitcoin.sipa.be. 3599 IN A 93.115.89.76 seed.bitcoin.sipa.be. 3599 IN A 108.11.187.129 seed.bitcoin.sipa.be. 3599 IN A 116.203.136.157 seed.bitcoin.sipa.be. 3599 IN A 15.164.169.200 seed.bitcoin.sipa.be. 3599 IN A 47.74.245.182 seed.bitcoin.sipa.be. 3599 IN A 74.98.242.97 seed.bitcoin.sipa.be. 3599 IN A 212.170.100.71 seed.bitcoin.sipa.be. 3599 IN A 59.110.18.37 seed.bitcoin.sipa.be. 3599 IN A 193.30.123.209 seed.bitcoin.sipa.be. 3599 IN A 217.125.246.37 seed.bitcoin.sipa.be. 3599 IN A 185.2.101.192 seed.bitcoin.sipa.be. 3599 IN A 94.26.190.7 seed.bitcoin.sipa.be. 3599 IN A 123.134.246.100 seed.bitcoin.sipa.be. 3599 IN A 78.47.168.239 seed.bitcoin.sipa.be. 3599 IN A 23.175.0.212 seed.bitcoin.sipa.be. 3599 IN A 5.2.194.97 seed.bitcoin.sipa.be. 3599 IN A 91.178.131.108 seed.bitcoin.sipa.be. 3599 IN A 173.212.207.249 ;; Query time: 271 msec ;; SERVER: 10.0.2.3#53(10.0.2.3) ;; WHEN: Thu Oct 31 15:16:59 UTC 2019 ;; MSG SIZE rcvd: 449 他のノードとの接続はディスク上のDBに保存する プロトコルバージョンのサポート vagrant@vagrant-ubuntu-trusty-64:~/bitcoin$ bitcoin-cli getnetworkinfo { "version": 170100, "subversion": "/Satoshi:0.17.1/", "protocolversion": 70015, "localservices": "000000000000040d", "localrelay": true, "timeoffset": 0, "networkactive": true, "connections": 3, "networks": [ { "name": "ipv4", "limited": false, "reachable": true, "proxy": "", "proxy_randomize_credentials": false }, { "name": "ipv6", "limited": false, "reachable": true, "proxy": "", "proxy_randomize_credentials": false }, { "name": "onion", "limited": true, "reachable": false, "proxy": "", "proxy_randomize_credentials": false } ], "relayfee": 0.00001000, "incrementalfee": 0.00001000, "localaddresses": [ ], "warnings": "" } コマンドがversionとverackのメッセージを使ってハンドシェイクを行う 相手のノードのバージョンとuser agentが表示され、ハンドシェイクが完了 ブロックチェーンの同期が終わったあとは、ブロードキャストされたブロックを受診してブロックチェーンを更新

P2PKH, マルチシグ

支払い形式によって、スクリプトの設定方式が複数存在
– ScriptPubKey

def self.to_address_script(address)
	hash160 = Bitcoin.hash160_from_address(address)
	case Bitcoin.address_type(address)
	when :hash160; to_hash160_script(hash160)
	when :p2sh; to_p2sh_script(hash160)
	end
end

– ScriptSig

UTXOを使用するには複数の署名が必要になる
m-of-nマルチシグはn人のうちm人が署名すればできる

ScriptPubKeyにスクリプトのハッシュを設定することで単純化したものがP2SH
ハッシュを用いてトランザクションに含まれるデータ量を少なくすることで取引手数料を低く抑える

ロックタイム(OP_CLTV, OP_CSV)
特定のUTXOを使用したトランザクションを設定したブロック高またはUNIXタイムまでブロックに含まれないよう制限をかけることができる

トランザクション

トランザクションはインプット、アウトプット、その他トランザクションに関わる情報を含んでいる
version 4byte 32bit符号なし整数
tx_in_count 1-9byte 可変長整数 インプットのリストに含まれるアイテム数
tx_in 可変 TxIn インプットのリスト
tx_out_count 1-9byte 可変長整数 アウトプットリストに含まれるアイテム数
tx_out 可変 TxOut アウトプットリスト
locktime 4byte 32bit符号なし整数 ブロックに取り込まれる値を制御

インプットの構成
hash 32byte char[32] 全てのビットが0
index 4byte 32bit符号なし整数 値は0xffffffff
coinbase data bytes 可変 可変長整数 コインベースデータのバイト数 2~100
coinbase data 可変 char[] 任意のデータ
sequence 4 32bit符号なし整数 値は0xffffffff

ビットコインではスクリプト言語を利用して電子署名と署名の検証を行なっている
アウトプットのscriptpubkeyには電子署名を検証する命令、インプットのscriptsigには電子署名をスクリプト言語で記述する

電子署名はUTXOの持ち主であることを証明する。署名には秘密鍵を使用
トランザクション -> sha256 -> sha256 -> signature hash -> ecdsa署名 -> signature -> signature -> トランザクション インプット0

トランザクション作成の工程
– インプットにセットするUTXOの準備
– トランザクション全体の作成
– インプットの作成
– アウトプットの作成
– 署名
– ブロードキャスト

ブロックチェーンのブロック

ブロックチェーンの仕様の修正はソフトフォークとハードフォークがある。ソフトフォークは古いブロックの仕様と互換性がある仕様の修正。ハードフォークは大きな仕様の変更。マイナーがフォークを採用するかどうかにかかっている

ブロック構造
4バイト: Block Size: ブロックのデータサイズ
80バイト: Block Header: ブロックヘッダ
1〜9バイト: Transaction Counter: ブロックに含まれるトランザクション数
可変長: Transactions: ブロックに含まれるトランザクションのリスト

ブロックの識別子はブロックハッシュとブロック高がある
getchaintipsで先端がわかる
vagrant@vagrant-ubuntu-trusty-64:~/bitcoin$ bitcoin-cli getchaintips
[
{
“height”: 0,
“hash”: “000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f”,
“branchlen”: 0,
“status”: “active”
}
]

マイニング処理
当初の設計ではnonceフィールドの値を順次変更しながらsha-256によるハッシュ値の計算を求め、そのハッシュ値がブロックヘッダのdifficulty targetフィールドで定められた難易度ターゲットよりも小さい数値であれば成功

現在は、Thash/sec, PHash/sec, EHash/sec
新規ブロックの作成と同時にマイナーが作成するコインベーストランザクションの領域を利用
コインベーストランザクションをextraNonceとして利用している
hash char[32] 32byte
index uint32_t 4byte
script bytes compactSize unit
height script
coinbase script None
sequence uint32_2 4byte

マイニング難易度はdifficulty target
target = 係数部*2**(8*(指数部-3))

def target(difficulty_target)
	exponent=difficulty_target[0..1].hex
	coefficient=difficulty_target[2..7].hex
	(coefficient*2**(8*(exponent-3)))
end

ビットコインの送金

取引手数料の設定
vagrant@vagrant-ubuntu-trusty-64:~/bitcoin$ bitcoin-cli settxfee 0.00001
true

bitcoin-cli sendfrom <送信元アカウント> <送信先ビットコインアドレス> <送信金額>

トランザクション内容の確認
vagrant@vagrant-ubuntu-trusty-64:~/bitcoin$ bitcoin-cli gettransaction 01307080d1961631b0da844024d8c842bd805dac38bfadb9ce5a771b6a55691a

トランザクションの一覧
vagrant@vagrant-ubuntu-trusty-64:~/bitcoin$ bitcoin-cli listtransactions

支払い請求のURI形式の標準がBIP0021として定義されている
walletの秘密鍵が漏洩すると、資産が盗まれてしまう
 → これってつまり、リミックスもwalletの秘密鍵が盗まれたって事??でも秘密鍵は暗号化していたと会見で言っていたみたいだが。。そういえば、suicaとか電子マネーの上限が決まっているのも、盗難の懸念を考慮してなのかもしれませんね。

オンライン状態をホットストレージ、オフラインをコールドストレージ
秘密鍵はコールドストレージに保管する

ルートシードとマスター秘密鍵
walletのホットストレージ、コールドストレージを挟んだ鍵の設計は非常に複雑だな。。。
リミックスの場合は、ホットウォレットの秘密鍵が全部盗まれ解読されたんかいな。
でも普通、秘密鍵のストレージには外部からアクセスできないように、ファイヤーウォール、ip制御、token管理とかするよね。