read.cash Log in
@liwi more from that month

接續前述 BCH 的 raw transaction ...這應該是最後一篇了 - . - https://noise.cash/post/1mr86g00 所以就我嘗試實作的過程來說,有什麼值得注意的地方呢?也或者說,如果能夠重頭來過,我會依下面的順序做。 1) 了解公私鑰、各種編碼轉換與 raw tx 格式 這邊還是推薦把 http://www.righto.com/2014/02/bitcoins-hard-way-using-raw-bitcoin.html 讀過一次,了解各個環節。而 Ken Shirriff 這邊連送上鏈的部分也是直接跟節點用 port 8333 作 TCP 連線完成手作。Ken Shirriff 這篇用的是未壓縮公鑰格式。 另外推薦 Royal Fork Blog 的這兩個圖解網頁 http://royalforkblog.github.io/2014/11/20/txn-demo/ http://royalforkblog.github.io/2014/08/11/graphical-address-generator/#noise 這邊用的是壓縮格式公鑰。 實作上用那種格式的公鑰不太重要,但了解一下有這些格式區別也是好的。 各種編碼轉換我都是自己 code,但搜尋一下網路上會有很多現成的網頁計算機。大部分都蠻好理解跟實現的,最麻煩的大概是 CashAddr 用到的 polymod 函式。這部分我用了公版程式碼(Python,但我沒用 Python 作所以只好改寫... - . -),知其然不知其所以然。不過這只有用來算 CashAddr 裏頭末八位 hex 時才會用到,跟 raw tx 沒什麼關係。 2) BCH 的 digest preimage 丟去簽名的東西 BCH 跟 BTC 很不同,原因是硬分叉後的避免重送攻擊的機制。preimage 格式的部分可以看: https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki https://apexpl.github.io/bitcoin_cash_sv_abc_transaction_signatures.html https://github.com/Electron-Cash/Electron-Cash/blob/master/electroncash/transaction.py BIP-0143 的 git 頁面下方也有一些 test data set,但都是比較繁複的情境。如果想要簡單一點的,可以參考: https://bitcoin.stackexchange.com/questions/71284/how-do-i-generate-the-bitcoin-cash-hash-preimage 但要注意他那個 hashOutputs 的部分似乎餵了不對的 P2PKH https://reference.cash/ 則有不錯的較有系統的 BCH 技術規格資訊整理,但我感覺對於本來不懂的人來說,或許不是那麼容易上手。比較像是開發人員自己的工具書 / 筆記。 我一開始因為先看 BTC 的 raw tx 跟簽署,有了簽署就是整個 raw tx 丟進去簽名的既定印象,所以一段時間一直在納悶為什麼 BCH 相關的找到的資訊都不是這樣。後來才理解,raw tx 格式跟 digest preimage 格式在 BCH 裡是兩回事。而如果找 Electron Cash 的 unsigned raw tx 來看,會有幾個看起來似乎是多餘的欄位。不知道是什麼原因,也或者就是程式內部用;raw tx 沒簽名反正都沒用。 有了 preimage 就可以丟雜湊函式算 digest,有了 digest 就可以簽名。簽名後就丟到 rax tx 格式裡。基本上都一樣,如果說有什麼要注意就是簽名後綴的格式碼要用 0x41,而不是太古鏈上的 0x01。 Sequence 跟 Locktime 現在似乎也都有自己的用途了,不過不理會也似乎不會有什麼問題。那麼所有的 raw tx 至此都備齊了,就缺董仔一個簽名。 3) ECDSA 簽名 我是直接用 openssl https://www.openssl.org/ 手做的過程中我也寫了一些簡單的 ECC 的操作涵式,理論上也是可以自己簽。但一來同時有太多 unknown 很難偵錯,再來 ECDSA 簽名的部分似乎也有格式一類的人工物,要找要看技術文件又會是一番功夫。另外 openssl 現在算是一個標準化了的工具,學會怎麼操作大概也是好的。最後基於安全性 ECDSA 用的是很大的數很大的群,所以估計這裏頭的演算法最佳化也是重要的文章。當然做 (1)的部分就都需要大整數了,所以應該是可以算。效率的話就未知,如果還要偵錯... 想想還是算了。 Openssl 會用到的指令有 https://www.openssl.org/docs/manmaster/man1/openssl-ec.html https://www.openssl.org/docs/manmaster/man1/openssl-pkeyutl.html 說起來 (1) 的部分很多跟 raw tx 實作沒有直接關係,但要用 openssl 的話就要把資料整理成他要吃的格式。所以到最後寫了幾百行,有大半都是在處理編碼。 Royal Fork Blog 上也有關於 ECDSA 的圖解說明 http://royalforkblog.github.io/2014/09/04/ecc/ 不過回頭看,我覺得他一些(重要的)地方交代得太過含混,會需要其他的參考。其中我一個疑惑是 29 跟 31 這兩個質數是怎麼來的。說穿了也沒什麼,29 是一個任意的質數選,定義了有限域 GF。31 則是選定了 Generator 之後,用定義的橢圓函數運算子能夠得到的元素數量,其中要另外把 0*G 也算進去。也就是說,31 是橢圓曲線套上有限域與某個 Generator 後得到的群的大小。我就是基於這些疑惑所以才自己寫了 EC 運算。選擇不同的 1*G 會得到不同大小的各種不同的群。基本上群越大越安全所以 Generator 的選擇是一個學問,比特幣用的 secp256k1 可以想成就是一個群的定義。那群的數量要怎麼算出來?群小的部分可以一個一個跑,但可以想見的這樣的密碼群一點都不安全。基本上安全的密碼群是沒辦法一個一個推演完的。有數學公式/演算法可以計算群的大小,很厲害吧?這是我在 EC 上最想進一步了解的。 但圖解就是方便,玩玩得些印象也是好的。@Ayukawayen 最近整理了一些 ECC 相關的文章,可以追一下,比如說:https://noise.cash/post/19zk4948 4) 廣播送上鏈 我是用 BlockChair 的廣播介面 https://blockchair.com/broadcast/ 其實這個介面蠻好的,如果你跟我一樣顯示 decode 錯誤,那麼其實就是在告訴你格式錯誤,沒辦法進行拆解。而如果格式表面上看起來沒錯,那 99% 問題是出在 varInt。如果你 (1) 的部分理解了,就會知道 raw tx 裡有些元素的長度不是固定的。所以在這種情況,解碼時會先讀一個紀錄著下一位鄉民有多長的 varInt,然後再把那位鄉民人肉出來。 如果只是想試看看能不能把廣播介面玩壞,也可以用 Electron Cash 產生 signed raw tx,然後更動一些欄位的 hex,就會得到對應的錯誤。因為我是做 ECDSA 簽名,所以 Electron Cash 裏頭要把 Schnorr 簽名關掉(Schnorr 簽名實作也是我之後想多了解的部分)。 我嘗試的過程中得到過如附圖的諸類錯誤: - 解碼錯誤 - CHECK(MULTI)SIG 錯誤(簽名無效) - Scriptpubkey 錯誤(上鎖碼格式錯誤) - 不明所以的簽名錯誤 最後不明所以的錯誤以後,死馬當活馬醫,我把 tx version 改成 0x02 就莫名其妙的成功了... 是有讀到一些建議/需要重簽的狀況的論壇討論,但沒有存下來。 大概 4 這樣。希望有激勵大家的一點興趣? 結果上來說真的沒什麼,就是一個重複發明輪子結果路上還會爆胎的過程。但這過程中得到蠻多體會的,也分心去亂玩了很多跟 raw tx 沒有直接相關的部分。 了結一樁心事... 結果好像挖了更多的坑 XD 這系列一共如下: - 發想 https://noise.cash/post/1nwjkn85 - 中本聰比特幣簽署設計的十萬個問號 https://noise.cash/post/lgw06k5j - WIF 與 legacy address 生成 (未壓縮格式公鑰) https://noise.cash/post/l4ng2z75 - 壓縮格式公鑰 https://noise.cash/post/lrxm2x79 - 為什麼要壓縮公鑰與比特幣的多重安全性設計 https://noise.cash/post/lw8wk3xj - 橢圓曲線公開簽署演算法 ECDSA 安全嗎? https://noise.cash/post/1xgrkn7n - 硬分叉與重送攻擊保護設計 replay protection https://noise.cash/post/1gkn4kvp - 回頭檢視 raw tx 與比特幣的 UTXO 設計 https://noise.cash/post/1mr86g00 - 終章... 本篇

4 comments

Log in to join in Reading is open to everyone. Replying needs an account.