Coldcardのファームウェア
こんにちは。AndGoのハードウェア担当の片山です。
前回はオープンソースのハードウェアウォレットのColdcard (https://coldcard.com/) のハードウェアについて解析してきました。カナダ初のハードウェアウォレットで,Micro SDカードへのバックアップできることが特徴的です。オープンソースのハードウェアウォレットでありながらATECC608Aというセキュアチップを搭載しています。今回はColdcardのGitHubリポジトリを探検し,ファームウェアについて見ていきたいと思います。早速リポジトリにアクセスしてみます。
早速リポジトリ(https://github.com/Coldcard)にアクセスしてみます。REAME.mdが表示されますので下の方のCode Ordanizationのセクションに移動します。各ディレクトリの説明が書かれています。
shared・・・シミュレータバージョンとマイコンバージョンに共通のコードが入っています。開発スピードを上げるためにテスト用にMacOS上でシミュレータを動かすこともできるもので,マイコンバージョンは実際のColdcard用です。ここにはこれらのバージョンに共通で使用するコードが入っています。主にPythonで書かれています。詳細については後述。
unix・・・シミュレータバージョン固有のコードが入っています。unixとありますが,MacOS上で動きます。
stm32・・・マイコンバージョン固有のコードが入っています。ビルドするとバイナリが生成され,Coldcardに書き込むことができます。
testing・・・ユニットテストのためのコードが入っています。
external・・・さまざまな外部モジュールが入っています。git cloneしてくると,ここだけで5.3GBの容量を消費しますので注意!
stm32/bootloader・・・出荷時に書き込まれるハードウェア固有のコードです。
hardware・・・回路図や部品リストです。前回【2022/02/02】紹介しました。
unix/work/MicroSD・・・シミュレータでSDカードを再現する部分です。
シミュレータでCOLDCARDを動かしてみる
シミュレータがついているので早速動かしてみました。基本的にはREADME.mdの手順にそって作業を進めるとMacOS用にビルドされてシミュレータが動きますが,手元の環境ではビルドに失敗してしまいました。
一つ目はffiというライブラリがうまく読み込めていないようでした。どうやらrubyに関係するもののようです。自分自身rubyは使ったことがないのですが,下記のコマンドでこのエラーは回避できました。
brew install gem
gem 'ffi', '1.9.21’
他には型に関する警告がいくつか出ていてエラーとみなされコンパイルが止まってしまうので(本当は無視しないほうがよいですが・・・),external/microfpython/ports/unix/Makefile より
CWARN = -Wall -Werror
の-Werrorの部分を削除しました。最後にunixディレクトリのsimulator.pyを実行するとシミュレータが起動します。動作中の動画は下から見れると思います。デバッグ用なのでセットアップされた状態からスタートします。ビットコインアドレスがいくつか表示されるのが確認できるはずです。
COLDCARDのファームウェアの開発言語
Coldcardのファームウェアはブートローダー以外の部分は主にMicroPythonで書かれています。マイコン用のファームウェアはハードウェアに近いということや,マイコンそのものの処理速度やストレージが限られていることもあり,オーバーヘッドが小さなCやC++で開発されることが多いです。例えば,パフォーマンスを気にするOSやゲームなどはC/C++で作られています。しかし,開発効率やメモリの安全性の面を考えるとC/C++ではなく,新しい言語を使いたいところです。Pythonは機械学習やデータサイエンスの分野,Webのバックエンドで使われることも多く,ポピュラーな言語です。このPythonをマイコンで使えるようにしたものがMicroPythonです。マイコンも性能が向上してきたのでMicroPythonでも十分に開発できるのだと思います。ちなみにTrezor OneのファームウェアはC/C++,Trezor Model TはMicroPythonで書かれていますので時代の変化を感じます。
ただPythonは非常にカジュアルに書ける一方で,言語そのものの変化が大きいことや,型を厳密に決められないことなどから,長期に渡って質が高いコードを書くのは厳しいような気もしています。ただC/C++も非常に古い言語でC++も拡張はされてはいるものの限界が見えてきており,次の言語としてはRustが注目されています。
ファームウェアを少し読んでみる
GitHubリポジトリからshare > main.py とたどっていくとエントリーポイントとなっています。more_setup()でブートローダーでやり残したハードウェアの初期化を行い,mainline()からメニュー画面の描画やキー操作の受付などをします。その後はメニュー画面でユーザーが行った操作によって他のコードが実行されます。わかりやすいものとしては,seed.pyにはシード関係の処理が書かれています。show_words(...)を見てみると,たしかにニモニックを表示してユーザーに記録させる処理がされています。
Coldcardの特徴としてペーパーウォレットを作成してPDFとしてmicroSDカードに書き込む機能があります。Coldcardが持っている秘密鍵からではなく,Coldcardの乱数ジェネレータで新たな秘密鍵を生成してペーパーウォレットを新たに作成する機能です。この機能はpaper.pyに実装されています。doit(...)あたりを見ると,秘密鍵・公開鍵ペアを生成している様子がわかります。
※paper.pyを読んでいたところ,「# rather than Tokyo, I chose Chiba Prefecture in ShiftJIS encoding...(ShiftJISエンコーディングのために,東京じゃなくて千葉を選んだ)」という奇妙なコメント行を見つけました。PDFを生成する際のplaceholder(ダミーの文字列)に使われているようですが,いまいち理由がよく分かりません。
ブートローダー
リポジトリのstm32 > bootloader にはブートローダーのコードを見ることができます。主にC言語で書かれていて,さらにバイナリもマイコンの中でも読み出すことができない特別な領域にMicroPythonで書かれたコードとは分けて格納されています。ここではハードウェアに近く,セキュリティに関する重要な処理がされています。例えばae.cなどはセキュアエレメントに関する処理が記述されています。ae_sign(...)では署名に関わる部分です。秘密鍵を指定して,OP_Signというコマンドで実際に署名している様子がわかります。
まとめ
今回はColdcardのファームウェアについて見てきました。ほんの一部しか紹介しきれませんでしたが,少しだけ,これで動いているんだという実感を持っていただけたのではないでしょうか。オープンソースですので,すべてのコードを検証は可能なようになっています。オープンにすることによってセキュリティが高まるという仕組みが非常に面白いと思います。非常に量が多く開発経験が無いとなかなかすべてを理解することができませんが,まずは,README.mdやコードに書かれているコメントなどを眺めてみると良いかもしれません。
次の記事
読者になる
一緒に新しい世界を探求していきましょう。
ディスカッション