2017/06/27

[zybo]ZYBO向けのLinux (1)

ZYBOのような組込み開発用のボードでOSが載る場合、ほぼメーカーがボード用のOSをリリースしていると思っている。
昔は「自分でがんばってね」という感じだったのだけど、提供するところが増えてきた今、使ってもらうためには「今すぐ使えます」を売りにしないといかんのだろう。

ZYBOはCortex-Aが載っているし、SDカード無しでもLinuxが動いているから、OSを動かしたいならLinuxがよいだろう。
ARMのCortex-Aだから、アドレスさえうまくやっておけばどのLinuxでもいいとは思うのだが、初っぱなから失敗したくないので、動くOSがあるならそれをまずは使いたい。


Zybo [Reference.Digilentinc]

これがZYBOを販売している会社のページで、右側のDesign Resourcesにいろいろファイルがある。

image

ここにPetalinux BSPというのがある。
XilinxはPeta Linuxというディストリビューションを使っているらしい。

https://github.com/Digilent/petalinux-bsps
ここからOSがダウンロードできるのかと思ったけど、Linuxが動きそうなサイズでもないし、かといってスクリプトしか載っていないようなサイズでもない。
そして、READMEにも何も書かれていない。。。


PetaLinux ツール
Xilinxのページで、右の「クイックリンク」にPetaLinuxがダウンロードできそうな項目があるのだけど、クリックしても行き当たらない。
英語ページだったら行くかと思ったが、そうでもなさそうだ。


では、ZYBOのリンクにあるPetalinux BSPが使えるのだろうと思ったけど・・・と、考えがぐるぐる回ってしまったのだ。


ここに、Xilinxが認識している動作OSが載っていた。
https://japan.xilinx.com/products/design-tools/software-zone/embedded-computing.html#os

いろいろある。

Xilinxのgithubにはkernelが置いてあった。
今の最新は、4.9.0のようだ。
https://github.com/Xilinx/linux-xlnx/blob/master/Makefile

kernelだけあっても困るので、ディストリビューションになっているものがよい。
PetaLinuxがよいのか、FPGAマガジン No.12ではYocto ProjectのLinuxを動かしているので、それがよいのか。。。


まあ、試すのは無料だから、Yocto Projectをまずは試すことにする。

2017/06/25

[xilinx]Vivadoの種類

Xilinxの開発環境は「Vivado(ヴィヴァドゥ?)」というようだ。
インストールしたものの、選択肢としてどれがよいのかさっぱりわからん。

いくつかインストールしたついでにAbout画面のスクリーンショットを撮ったので、載せておこう。


Vivado HLS 2017.2

image


Vivado 2017.2

image


xsdk 2017.2

image



image

Design EditionとSystem Editionがあるのだけど、どっちがどうなのだろう?
Systemの方が上っぽい感じはするが。

Vivado Design Suite
Design EditionとSystem Editionの両方とも「パーシャルリコンフィギュレーション」というやつが追加費用無しでできるが(保証期間内だけ?)、WebPACK Editionは追加費用がかかるらしい。
が、これではわからんなぁ。。。


Vivado Design Suite 評価版および WebPACK
一覧表があった。
違いは、"System Generator for DSP"の有無のようだ。
画面の選択肢に書いてあるとおりだな。


いや、そもそも私はDesign Editionを選択したのだけど、実はよくある30日間の無料試用版なのだろうか。
Installing Vivado [Reference.Digilentinc]
ZYBOの販売先にあるインストール説明でも、WebPACKと書いてあるし。


今回、ZYBOはSDSoCのライセンス(購入したボードのみという制限はあるが)もセットにしたので、SDx開発環境というものもインストールした。
というよりも、先にこちらをインストールして使っていたのだが、後述する問題点があったので2017版をインストールしたのだ。



Xilinx_SDSoC_2016.4_sdx_0310_1_Win64.exe

image

インストール画面。
ZYBOにはZynq-7010が載っているから、それだけ選べばよいよね?
これは何回目かのインストールしなおしをした画面なのでCable Driverのチェックは外している。

インストールすると、Vivadoとxsdkも一緒にインストールされた。



Vivado 2016.4

image


image


で、SDx開発環境の何が問題だったかというと、SDx IDE 2016.4だ。

Windows10のバージョンによるのかもしれないが、うまく起動できなかったのだ。
ZYBOのチュートリアルに書かれてある起動方法では、スプラッシュ画面が出てしばらくすると落ちる(%APPDATA%\Xilinx\Vivadoにhs_err_pid***.logというファイルを見ると、Java自体が落ちている)し、単体だと起動できるのだけどもFPGAに関する機能が使えないのだ。

image

たぶん、ツールバーの空白になっているところにFPGA関連のボタンが出るはずなのだが、無い。
Xilinxメニューにも、何も出てこない。
プラグインが起動できなかったとか、そういう理由だろうか。

image

こちらが、2017.2のXSDK。
違いは明らかじゃろう。


ただ、「SDSoC」という名前が入っているのはSDx IDEだけなので、C/C++でFPGAのコード?が書けるというSDSoCという機能を使いたかったらこれしかないのかもしれん。


SDx IDEはeclipseで、パースペクティブは「SDx」というものになっていたのでcustomize画面を開いた。

image

toolbar1というやつが表示されていないだけか・・・?
3つともチェックして再起動すると、アイコンが出てきたし、押すとチュートリアルにある画面も出てきた。

image


VivadoからのLaunchはできないけど、これでSDSoCの機能も使えるのであれば問題ないと思う。
問題があるとすれば、私がSDSoCが何なのかわかっていないことと、そもそもFPGAがよくわかっていないということだろう。
FPGAマガジンNo.16にはSDSoCのことも書いてありそうだから、買ってみるか。

2017/06/24

[zybo]ZYBOを動かしてみよう

いきなりだが、XilinxのFPGAであるZYNQ7010が搭載されたZYBOというDIGILENT社のボードを動かしてみた。
むかしから、FPGAというものを動かしてみたかったのだけど、仕事でしか見たことがなかったので、個人で使えるような時代になっていると思っていなかったのだ。

しかも、Linuxが動くARMのCortex-Aが載ったボードまであると言うことで、そろそろやってみてもよい時期だろうと判断したのだ。
判断したというか、やってみたい熱が高まっただけだがね。


ZYBOは、秋月通商さんで購入。

image

比較のためPaSoRiと一緒に撮影したが、小さいねぇ。
Cortex-Mに比べると大きいけど、そこと比べるものでもないだろう。


勢いで購入したものの、そもそもFPGAを自分で構成したことなどないので、まずは一連の流れをやっているところを探しました。

6. Zynq Verilog-HDLをZynqに書き込みFPGAを使う – yuki-sato.com
【Zynq】ZyboでPLのみ使用してLチカしてみた

この2箇所を見て、動かすことができた。
私はVerilogの方を使ったが、ハードウェア記述言語(HDL)としてはVerilogかVHDLが使えるようだ。
Wikipediaによると、厳密には"Verilog"はエミュレータのことらしい。
VHDLはVerilog HDLの略ではなく、別の言語。
誰がこんな紛らわしい名前にしたんだ・・・と思ったが、VHDLの"V"はveryらしいし、Verilogは名前の由来が分からないので、どっちがどうのという話でもなさそうだ。


なお、Windows10にインストールする際はここを参考にした。
VC++のランタイムって、該当するバージョンが入っているだけではダメなのか?
謎は残ったが、今回は困らないので削除した(Vivadoの2017版は関係なく動いたが、SDxは2016版が自動的にインストールされるので、そういう制約になってしまうようだ)。
FPGAの部屋 Vivado や Vivado HLS が Visual Studio 2012 Visual C++ Runtimeのインストールダイアログが出て起動できない


やっていることを、整理してみよう。


まず、プロジェクトを作成する。
「RTL Project」を選ぶそうだが、RTLとはなんだ?

Register Transfer Levelの略
レジスタ転送レベル - Wikipedia

CPUのレジスタとは違うもので、ごくごく小さな回路を「これはレジスタね」と決めて、そういうレジスタからレジスタへのINPUTとOUTPUTを書いていくもののようだ。

Lはlanguageじゃなくて、levelなのが気になる。
Wikipediaのはそこまで書かれていないが、「ゲートレベルよりも抽象的な記述レベル」と書いてあるので、何かのものを指す用語ではなく、切り口というか考え方というか、そういうもののようだ。
ゲートレベルがアセンブラだったら、レジスタ転送レベルはC言語、みたいな感じかもしれん。


プロジェクトを作ったら、HDLで内容を書く。
こちらを参考にVerilogで書いた。
引数?が昔のC言語っぽいので気になったが、今のC言語っぽく引数内に型?を一緒に書いてもよいようだ。

module led(output led, input button);
    assign led = button;
endmodule

C言語っぽく、{}で囲みたいところだが、それは我慢だ。

なお、ZYBOに転送すると Vivadoの画面がHardware Managerになって、Verilogのファイルが載っていたナビゲーションが消えてしまう。
元に戻したい場合は、左側の"Flow Navigator"からProject Managerをクリックするとソースファイルが入ったツリーが出てくる。


次は、Verilogのoutputやinputで付けた名前と、実際のポートを割り付ける作業だ。
"RTL Analysis"内の"Elaborated Design"を選択して、レイアウトを"I/O Planning"にして行っているのが、それだ。

画面には、FPGAのBGAっぽいものが表示されるが、そっちは見方がわからん。
画面のしたにI/O Portsという一覧が表示されていて、Verilogの引数にしたものが出てくるようだった。
「I/O StdをLVCMOS25などに切り替えましょう」と説明されていたが、「Low Voltage CMOS 2.5V」という意味なんじゃなかろうか。
ZYBOのドキュメントには、3.3Vで吊られている図が載っていたので、2.5Vくらいにしようぜ、ということかもしれん。


その後は、「Run Synthesis」「Run Implementation」「Generate Bitstream」を実行すると、FPGAのPLに転送するデータができるようだ。
ツールバーに3つ並んでいる。

image

しかし、用語のそれぞれがわからん。

まず、Synthesis。
単語としては、合成とか組み立てとか。
Xilinx Synthesis Technologyを略してXSTと呼んでいて、合成ツールという位置づけのようだ。

合成は、論理合成を指しているのだと思う。
だからXilinx専用の言葉ではなさそうだ。
Wikipediaの説明では、HDLで書かれたものをRTLまで変換するツールのようだ。
HDLがRTLかと思っていたけど、もう少し高級ということか。
HDLがC言語としたら、RTL相当なものがアセンブラで、それを論理ゲートレベルまで変換したら機械語、くらいなのかな。


次はImplementationだが、ソフトでいえば実装だが、FPGAではこのページの「デザインインプリメンテーション」に当たるのかな。
半導体技術解説:いまさら聞けない FPGA入門 (3/3) - MONOist(モノイスト)

詳しいことはわからんが、コンパイル後の最適化みたいなものか。
そういえばGCC4から中間言語に変換して最適化するようになったが、あれもRTLと呼ばれていたな。
GCCのRTLは、Register Transfer Languageのようだ。
GCC 4 について学ぶ


そしてBitstream。
Monoistのページではデザインインプリメンテーションの中に入っているが、FPGAに書込むことができるデータを作る工程のようだ。
拡張子はbitで、プロジェクト名がprojだった場合、proj/proj.runs/impl_1/proj.bit、というところにできているようだ。


そして、これを"Program and Debug"を使ってFPGAに転送すれば動くようになる。
どうも、FPGAに焼くというよりは、転送する、という感じがしている。
電源を入れ直すと動かなかったからだ。
PL部だけ電源OFFにすることもできるようなので、PS部から毎回転送するイメージなのかもしれん。

2017/06/22

[c/c++]引数が多いことに対する抵抗が薄れてきた

関数を作るとき、あまり引数が多いのはよろしくない、と教えられて育って(?)きた。

もちろんそれには理由があり、C/C++コンパイラはある程度の数までは引数をCPUのレジスタで引き渡し、それ以上になるとスタックメモリに入れて引き渡すからだ。
C言語の規格書を読んだことがないので決まりなのかどうかは知らないが、メーカー製のコンパイラ仕様なんかを読むとだいたいそうなっていた。


これはARM Cortex-AのARMv8-Aのようだが、Argument registersということで8つ確保してある。。。のだと思う。
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0024a/ch09s01s01.html

別の環境で、Cだと4つまで、C++だと3つまではレジスタ渡しするというのも読んだことがある(thisで1つ取られるからね)。
CPUによってレジスタの数や使い方が違うだろうから、全部同じではないだろう。


以前はけっこう気にしていたのだが、そんなに効果があるのかも気になっていた。
引数をたくさん与えないといけない関数は、だいたい使用頻度が少ないものが多かったからだ。
使用頻度があまりにも多い場合は、マクロ関数なりinline関数にするとそこそこ対応できるし(ROM容量との兼ね合いにもなるが)、みんなが使うのでstaticなどでグローバル変数にしているから渡す必要がなかったり。

引数を渡すということは、モジュールと切り離したいという意思が強いだろうから、そういうのはstructにして渡せるようにし、グローバル変数みたいにして保持するときもstructのままで持っておくと渡しやすい。


いや、何の話をしているかというと、引数が多いのはよろしくない→じゃあstructを用意して代入してポインタで渡す、などということを自分でやっていたからだ。
それって、スタックにためて渡すのとあんまり内容として変わらないけど、実装の手間だけ増えてるよな、と漠然と思っていたのだ。

そんなことをするくらいだったら引数が多いままの関数を作ってもよいし、そもそもそういう関数を作らなくていいような構造にできるした方が効率いいんじゃないの、という「引数が多いのはよろしくない」という警告だったのかもしれない。


そんなことを自分で作った引数8個の関数を見ながら思った。

[mbedTLS]2.5.1リリース

mbedはmbedでも、mbedTLSだ。

mbed TLS 2.5.1, 2.1.8 and 1.3.20 released - Tech Updates


私にとって特に大きな機能追加はないのですが、楕円曲線モジュールがハードウェアアクセラレーションに対応したようだ。
ECCを持っているマイコンだと重宝しそうだ。
Nordicのチップだと、micro-eccというライブラリを使っていたと思うから、あれには載ってないのだろう。

だいたい、楕円曲線モジュールの略語がよくわからん。
ECC(Elliptic Curve Cryptography)のような気もするが、mbedTLSはECP(Elliptic Curve Point)だ。
ECCだと、メモリの方が引っかかりやすいので、個人的にはECPの方がありがたいのだけど、どうなんだろう?

それに、楕円曲線暗号と一言で言っても、曲線の種類はたくさんあるから、それが全部マイコンに載っていることはないだろう。
どういう使い方をするのかは気になるな。


ともかく、mbedTLSはバージョン系統が3つくらいあるようだから、それぞれ最新版を利用するようにした方が良かろう。

2017/06/21

[linux]ほどよい通信用ライブラリはないだろうか?

ずっとやっている、Linuxでソケット通信でマルチスレッドなのがうまくいかないシリーズ。

安定してきた気はするものの、あっちでmutexのlock競合、こっちでlockとlockの隙間に割り込まれる、など、自分のまぬけな実装が目に余る次第だ。

こういうのって、MQTTのときにpahoを使ったように、ほどよいライブラリがないものだろうか?


似たような質問があった。
Best C/C++ Network Library - Stack Overflow

いいねぇ、君。
しかし、多いよ! この人が挙げただけでこんなにあるのか。
3年前だから、今だとまだあるのかもしれん。


自分が作っていたライブラリの部分はCで書きたいのだけど、通信とかアプリの部分はC++でもよい。
そうなると、ここの全部が選択できる対象になってしまうのだ。

使ったことがあるのは、POCOとlibcurlくらいか。
今回はTCPでプロトコルを作るので、libcurlはそぐわないと思う。
POCOはえらく多機能だった記憶があるくらいだ。
ここから見てみるか。

POCO C++ Libraries - Reference Library
うわあ、なんでもあるわ、この子。。。
普段の組込みライブラリからすると、目が回りそうだ。
Socketも使えるようだし、サーバもやってくれるようだから、これで事足りそうな気もする。


いや、待て・・・。
こんだけ便利なライブラリがあるのだから、逆に今回みたいに特定用途に特化したライブラリもあるのかもしれない。

いろいろ考えたが、これってP2Pというやつでよいんじゃなかろうか。
相手から受け付けるし、相手にも接続を求めるし、でも接続関係は1対1だし。


P2P library for C++ - Stack Overflow

一番上はlibtorrentだが、これはbittorrentの実装らしいから、汎用P2Pではないのだろう。
boost-asioは、P2Pで使うと便利だよ、ということかな。
libboostって、15年前くらいに見てそれっきりだな・・・。


その次のlibniceも、RFC5245の実装などと書いてあるから、特定のP2P実装なのだろう。
MsgConnectというミドルウェアも紹介されていたが、これは製品のようだ。
うーむ。


いや、これは私の考え方が悪かったようだ。
P2Pのフレームワークが欲しい、といった場合、だいたいは「P2Pのネットワークが欲しい」と思うだろう。
やりたいことは、P2Pで何かをする、であって、P2P環境を作るための何か、ではないのだ。


とすると、やはり最初に載せたC/C++の通信ライブラリと、何かスレッド間通信を便利にするライブラリを組み合わせるのがよいということだろうか。

定番が見つけにくい分野って、大変ですわ。。。

2017/06/20

[bc]秘密鍵を渡すのか…

先週出ていたニュースリリース。

【news release】仮想通貨とFeliCaを連携させた決済手法の開発と検証を実施-NEWS


うーーーーん・・・・・・・。

Blockchainに関わる実装として、いくら安全だからといって秘密鍵を渡すというのはどうなんだろうか?
FeliCa的な文化であればそれでよいのかもしれないけど、うちだと案が出た時点で却下されるな。
タンパ性がどうとかじゃなくて、Trustlessじゃないという理由だ。
まあ、Trustlessって何を指すんだよ、という話はあるだろうけど、秘密鍵を相手に渡す行為は十分相手を信用した結果しかできないよなぁ、と思う。


たぶんFeliCa内でトランザクションの署名はできないだろうから、FeliCaを絡めたければこうなるのだろう。

Type-Bだったらどうなんだろうか?
マイナンバーカードの中には、RSAの署名をする機能があったはずだ。
マイナンバーカードでSSHする - AAA Blog


それと、通常はアドレスを1回使うと、新しくアドレスを作り直してお釣りを転送すると思うが、そこはどうしたんだろうか?
testnetで実験するときは同じアドレスに送金することもあるのだけど、unspentなアドレスを使い続けると秘密鍵が解析されやすくなるんじゃなかろうか。

通常のウォレットは、seedを決めたら、あとは鍵の世代だけで秘密鍵を管理できるようになっている。
だから、seedが漏れたらおしまいなのだけど、秘密鍵の1つが解析されて見つけられたとしても他の秘密鍵には影響がないようになっている・・・らしい。
実装はしたことがあるのだけど、理論はよくわからんかった。


「パソコンやスマホのウォレットだって、PC内に置いてるだけやん」といわれればそれまでだし、Blockchainに関する実験としては他に比べるとかなり考えられているように感じるから、FeliCaでトランザクションの署名ができるようになるまでがんばってほしいものだ。

[linux]スレッド間のやりとりをバッファ経由に変更

なんだか、何のために記事を書いているのかわからなくなってきた・・・。

やりたいのは複数プロセス間のソケット通信。
プロセス間は1本のソケットでつないでいる。
直接通信できるのは接続した相手だけだが、転送してもらうことができる。


起きているのは、双方から同時に転送が行われると、どこかで止まるという現象。
排他をかけたり、状態を持って止めたり、あれこれ悩んでいる。
おかげで、元のソースに戻れないくらいだ。。。


前回考えた最後の図を載せよう。

image5

書いてある内容は無視して、線だけ見ていく。
A-B間、B-C間はソケット通信だ。
では、Bの中の点線は何かというと、スレッド間のやりとりになる。

スレッド間といっても、相手にソケットを送信したいだけなので、データパケットを作って相手のsocket descriptorを使って送信していた。
が、これはなんとなくよろしくない感触がある。
いくらsdがわかって送信できたとしても、やはり相手の通信路は相手のスレッドに処理してもらうのが筋なんじゃなかろうか。


しかし、スレッド間通信ってどうやるものなのだろう?
今回はソケット受信をpoll()しているスレッドがあったので、そこでタイムアウトするようにし、他スレッド処理要求ありフラグがあったらその処理をする、ということにした。
以前は関数呼び出しだったのでメモリを直接見せていたが、今回は時差が発生するので別にメモリを確保するようにした。

あー、キュー方式にして、キューに入っていたら処理をする、というやり方の方が良いな。。。
他スレッドからの要求なんていくつやってくるか決められないし、数を決めたとしてもあふれるようなら待たせないといかん。


まだフラグを立てるやり方だが、この方式に変更したところ、急に安定しだした。
困ったことに、動かないときは動かない場所を見ればよかったのだが、動き出したように見えると流れが期待通りかどうか確認するのが難しい。
一方向の通信だったらもともとうまく動いていたので、期待するタイミングでピタッと衝突できないと確認できんのだが、それってできるきがしない。。。


ともかく、みんなこんなプログラムを作るときどうやってるんだろう??
私が知らないだけで、実は便利なフレームワークやライブラリがあるのだろうか。

2017/06/18

[linux]通信による衝突はどうやって回避するとよいのかがわからん

昨日の続きだが、わからんシリーズだ。


マルチスレッドで並行に動かしたいわけではないので、終わるまで待たせればいいやん、という結論になった。
今回のプロトコルでは待たせても、処理さえしてくれれば問題ないのだ。

ただ、相手に再送してもらうわけにはいかないので、自分で処理が終わるまで待たせることにした。
mutexではなく、状態変数を持たせ、処理中だったら1秒ごとにチェックして終わったかどうかをループで監視することで待たせることにした。
volatileにしてwhileで回せばいいだろう。


そしたら・・・こういう現象が起きた。

image

あー、そうだね。。。
mutexだろうと状態変数だろうと、待たせるということはそのコンテキストが止まってしまうのだ。
コンテキストを止めたいのではなく、コンテキストで行われる処理を後回しにしたいだけなので、これではダメなのだよ。



じゃあ・・・どうしたらよいのだ?
Cが送信するタイミングではBからデータが来るなんてことはわからない。
だから送信して、このコンテキストはC→B→Aの送信だ、と考える。

しかし、Bからすると先にAから受信しているのでA→B→Cと動くのが自然なので、そういうコンテキストだと考える。
どちらも間違ってはいないのだが、このままではBはCからの受信を待機させるし、CはBからの受信を待機させて、これはこれで流れが止まってしまう。

Aが送信する前にCへ連絡できればよいのだけど、そういうルートはない。
だから、事前に知らせる方法はない。


相手と自分間でどちらかに送信に対する優先度を持たせるとどうだろうか。
幸い、A, B, Cはユニークな識別子を持っていて、その識別子は相手も知っているため、機械的に大小を決めることができる。

  • A>B, B>C : BはCより強いので、Aからの転送を優先させる
  • A<B, B<C : CはBより強いので、Aからの転送は待たせてCの転送を優先させる
  • A<B, B>C : BはCより強いので、Aからの転送を優先させる
  • A>B, B<C : CはBより強いのでB-C間はCの転送を優先させたいが、A-B間はAの方が強いので、Aの転送を優先させたくなる。AとCの強さで決めるしかないか?

最後のパターンでAの方が強かったとしても、CはAを知らないので、「俺はBより強いんだ」と考えてしまうだろう。
データに「あちらのお客様からです」というような情報があれば比較もできるが、それもない。
ダメか・・・。


ここでは一部だけ切り出しているが、実際のプロトコル仕様としてはシーケンスがクロスすることについては規定していないし、クロスしても特に問題はない。
実装の都合でブロックしようと考えただけだ。
もしかすると、ブロックできないことがわかっているから、そういう書き方をしているのかもしれない。

最初はブロックせずに実装していたのだけど、シーケンスとして「お互いの送受信状況を比較する」というようなものがあり、それが相手の転送によって割り込まれると、相手は転送データを受け取っているがこちらはまだ、というタイミングが生じてしまい、比較NGになってしまうのだ。

image


今回のように幅広くブロックするんじゃなくて、比較するぞ、という区間だけ転送を止める方が良いのか。
相手から比較データを送ってくるのは、相手がsendした後だということが決まっているので、相手のsendを受け取ってから比較が終わるまでの間だけ転送をブロックすればよいかもしれん。


いやー、難しい、難しいですよ。。。

2017/06/17

[linux]ある区間はスレッドを切り替えて欲しくない場合

まだまだLinuxのマルチスレッドで悩んでいる。


今起きているのは、こういうやつ。

image

丸いのは、mutex_lockだ。
ソケット通信で相手に送るプロセスと、それを受信したらもう片方に中継して送信するプロセスがいて、中継するプロセスはスレッドで相手と接続している。
相手に送信する前にmutex_lockするようにして、lockできたら送信している。


通常はそれでよさそうなのだけど、図のBがほぼ同じタイミングで送信データを受け取ったときに問題が発生した。
Aからの送信をBのA側スレッドが受け取り、ロックを掛けてC側のスレッドに渡そうとするのだが、その直前にスレッド処理がC側スレッドに切り替わり、そちらもロックを掛けてA側のスレッドに渡そうとする、という状況が起きてしまった。。。


こういうときって、どうするのだろうか?
各スレッドを貫くようなmutexを用意して、切り替わって欲しくないタイミングでlockするのがよさそうな気がする。

ただ、こうも思ったのだ。
「スレッドが切り替わらなければいいだけやん」と。
割り込み処理中に多重割込みにならないように割込み禁止にするようなイメージだ。
ディスパッチ禁止とかクリティカルセクションとか、そんな用語でよいのだろうか。


スピンロック、が一番それっぽい気がするが、これはkernelの中でしか使えないのか?
ぐるぐるとループを回して、条件が合うまで抜けない、というシンプルなしくみらしい。
RCUとかいうのもあるが、そもそも読んでいるのが『Linuxカーネル2.6解読室』だから、kernelで使えるしくみを紹介しているのだろう。


などと書いていって気がついたが、そもそも上記の処理ってマルチスレッドにしたのは複数の相手と接続したかったからであって、接続した相手と同時に通信をする必要がないことに気付いた。

つまり、これでいいやん。

image

プロセスとしてmutexを持っていて、誰か最初に処理を始めた人が全部握ってしまえばよいのだ。
終わってから動いたとしてもそれほど問題ない気がする。

整理するって、大切ですね。

[linux]ソケット送信した回数と受信する回数は関係がない

Linuxで、マルチスレッドで、ソケット通信するアプリを作っている。
ああ、慣れていない、慣れていないのだよ。。。


バグがいくつも出てきて困っているのだが、その1つに「こちらは送信したのに相手が受け取っていない」という現象があった。
write()は失敗していないし、そんなに取りこぼすようなところでもないし。

ログを見直していると、思ったより大きいデータ長の受信を行っているところがあった。
まさか・・・と計算すると、2つwrite()したデータ長と同じでした。
えー、write()って2回呼んだら、送信も2回で行ってくれるもんじゃないの??



Linux ソケット・プログラミングの 5 つの落とし穴

これの5番目、「落とし穴 5. TCP におけるフレーミング前提」か。
ええ、前提にしていましたとも。

今回はデータ長が載っているプロトコルでは無いので、解析しながらじゃないとデータ長が分からない。
が、今は受信したデータを解析する、というように作っているので、大幅な改造が必要になりそうだ。
ああ、慣れていない、慣れていないのだよ。。。

2017/06/14

[mbedtls]keypairはスレッド間で共用するものではない

数日前、mbedTLSの楕円曲線署名と検証は排他した方が良いのかもしれん、という記事を書いた。
(実は、こそっと追記した。)

http://hiro99ma.blogspot.com/2017/06/mbedtls.html


しかし、mbedTLSの設定に MBEDTLS_THREADING_CやMBEDTLS_THREADING_PTHREADがあるので、少なくともLinuxで両オプションを有効にしていたら大丈夫で、自分のコーディングがよろしくないんじゃなかろうか、という感触が少なからずあった。
少なからずというか、今までの経験上、よく使われているライブラリで結果が変だったときは、だいたい自分の書き方が悪いときだったというだけだが。

Thread Safety and Multi Threading: concurrency issues - Knowledge Base - mbed TLS (Previously PolarSSL)


モヤモヤしていたので見直しを行ったところ、mbedtls_ecp_keypairを共用している(自分が)ことが分かった。
ただ、mbedtls_ecp_group_load()でgrpメンバを設定して使う、という使い方しかしていないので、グローバル変数でもよいだろうと思っていたのだ。

が・・・実装しているうちに「署名の検証ってmbedtls_ecdsa_read_signature()にmbedtls_ecp_keypairをmbedtls_ecdsa_contextでキャストすれば使えるやん、ということに気付いてしまった。

//mbedtls/ecdsa.h
typedef mbedtls_ecp_keypair mbedtls_ecdsa_context;

そう、楕円曲線の検証だけgrpではなくkeypair全体を使っていたのだ。
そして、mbedtls_ecp_keypair構造体はメンバとして秘密鍵や公開鍵を持つようになっている。
実装までは確認していないが、署名の検証にそれらが使われているのは当然だろう。


いくらスレッドセーフだったとしても、書き換える対象の変数を共用していては意味が無い、というわけだ。


では、mbedtls_ecp_groupだったら共用させても大丈夫かなー、と思ったのだが、mbedTLSのインターフェースとしてはconst付きとconstなしがある。

さすがにconstなしのところを共用するのは同じ事態を引き起こすことになるだろうから、共用は止めて毎回スタックで設定するようにした。


共用で気にしているのは、mbedtls_entropy_contextとmbedtls_ctr_drbg_contextだ。
RNGが使いたかったし、毎回設定するようなものでもないと思ったのでグローバル変数として持っている。
mbedTLSのサイトでは、EntropyとCTR-DRBGはリストに載っているのだが、これは何のリストだ?
init/free()があって、メインスレッドから呼びなさい、と言っているようだが・・・。

mutexの初期化と解放をそこで行っているからメインスレッドから呼べ、ということかな?
だったら、他のところは別スレッドから呼んでもよいということになろう。

読む解くのが苦手ですわ。。。

2017/06/11

[c/c++]同じidでmsgsnd()してmsgrecv()すると、自分で読める

Linuxで2つのプロセスを作っていて、片方がサーバのように待ち受け、片方の要求に対して応答するようなしくみを作っていた。
どういう方法がよいのかわからなかったので、メッセージキューというものが見つかったので、msgsnd()とmsgrcv()でやろうと考えた。


最初は、クライアント側からサーバ側に要求してサーバ側の標準出力に結果を出していたのだが、それだと面倒なので、結果をクライアントに返してもらうように変更した。

何も考えず、ftok()でkeyを作り、msgget()でidを取得し、それを使っていたのだ。
が・・・動いたり動かなかったりする。
特に複雑なことはしておらず、サーバ側はmsgrcv()で待ち、クライアントがmsgsnd()したものを受信したら、結果をmsgsnd()で返してまたmsgrcv()で待ち状態になる、というだけだ。


悪かったのはいつものように私で、サーバがmsgsnd()して結果を書込んでからmsgrcv()にさっさと移行してしまうため、クライアント側がmsgrcv()で受信する前に自分で読み取ることがあったのだ。
だから、うまく行ったり行かなかったりという不安定な動きになっていた。

msgrcv()するとキューから消えてしまうので、mtypeで見分けても、もう遅い。
こんなことだったら、共有メモリにした方がやりやすかったんじゃなかろうか。


今回は、ここはまだ重要なところではないので後から見直すとしても、取りあえずでよいので回避できればよい。
どうするかというと・・・

msgrecv();
受信後の処理();
msgsnd(結果);
sleep(1);

うん、1秒くらい置いておけば相手は読んでくれるからよいだろう。

あー、ださださだ...

2017/06/10

[c/c++]3項演算子とifはそこまで変わらない

判断して代入するだけ、という処理はしばしば書くと思う。

2択の場合、私は三項演算子を使うことが多い。
ただ、3項演算子で書くと1行が長くなりすぎることがあり、そういうときは改行したりする。

そういうとき、改行するくらいだったらif文で書けばよいんじゃないの?

という声がよぎるのだ。

やることは同じなので、結果として同じバイナリになるのだったら、その時の気分だったりコーディング規約で書けばよいのだけど、もし高速になる要素があるのだったら推していくのもありだろう。

gccで確認しよう。


int main(int argc, char *argv[])
{
    int vol;
    if (argc == 1) {
        vol = 2;
    } else {
        vol = 1;
    }
    printf("vol = %d\n", vol);
    return 0;
}


int main(int argc, char *argv[])
{
    int vol = (argc == 1) ? 2 : 1;
    printf("vol = %d\n", vol);
    return 0;
}


これといった特徴はないコードだ。
argcを使ったのは、なんとなく最適化されなさそうだと思っただけだ。

結果を先に言うと、Bash on Windowsのgcc(gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609)では、最適化あり(-O1以上)にすると同じになった。
最適化するのであれば、どっちでもよいと思う。
何らかの理由で最適化しないのであれば、三項演算子の方が短くなった。



最適化無し(-O0)でコンパイルした結果。
右がif、左が三項演算子。

image

1と比較して一致しないならL2にジャンプして1を代入するという処理は同じだが、ifは直接-4(%rbp)に突っ込んでるのに対し、三項演算子は%eaxに突っ込んだ後で-4(%rbp)に代入している。
三項演算子のそれぞれで処理してレジスタに入れて、それを代入させる、ということだから、うん、確かにそういう動きですな。

2017/06/08

[ios]NFCNDEFPayloadはベタのpayloadなのかな

iPhoneを持ってないし、今のところ買う予定もないのだけど、NFC関連のAPIがiOS11から載りそうだということなので、少し見ておく。
なお、いま(2017/06/08)はまだβ版なので、正式版になる頃には状況が変わっていると思う。

NFCが載ったiOSならどれでもいけるのかと思ったが、iPhone7以降ということで、iPhone6はダメらしい。
なんでだろう、ハード的にそうなってるのかな?


見ておく、といったものの、iOSの挙動を知らないし、Swiftも知らないので、雰囲気だけで読んでいきます。
(間違い多いと思うけど許してね、の別表現。)


https://developer.apple.com/documentation/corenfc

大きく4つに分かれている。

  • Reader Sessions
    • class NFCNDEFReaderSession
    • protocol NFCNDEFReaderSessionDelegate
    • protocol NFCReaderSessionDelegate
    • class NFCReaderSession
  • NFC Tags
    • protocol NFCTag
    • class NFCTagCommandConfiguration
  • NDEF Messages
    • class NFCNDEFMessage
    • class NFCNDEFPayload
    • enum NFCTypeNameFormat
  • Errors
    • struct NFCReaderError


classとprotocolというのが並んでいる。。。
Swiftのprotocolは、Javaのinterfaceみたいなものらしい。

全部羅列したら、何か分かるだろうか?

[Reader Sessions]
  class NFCNDEFReaderSession
    init()
    protocol NFCNDEFReaderSessionDelegate

  protocol NFCNDEFReaderSessionDelegate
    readerSession(didDetectNDEFs)
    readerSession(didInvalidateWithError)

  protocol NFCReaderSessionDelegate
    isReady
    begin()
    invalidate()

  protocol NFCReaderSessionProtocol
    isReady
    begin()
    invalidate()

  class NFCReaderSession
    delegate
    sessionQueue


[NFC Tags]
  protocol NFCTag
    isAvailable
    session
    type
    enum NFCtagType
      ISO15693

  class NFCTagCommandConfiguration
    maximumRetries
    retryInterval


[NDEF Messages]
  class NFCNDEFMessage
    record

  class NFCNDEFPayload
    identifier
    payload
    type
    typeNameFormat

  enum NFCTypeNameFormat
    absoluteURI
    empty
    media
    nfcExternal
    nfcWellKnown
    unchanged
    unknown


[Errors]
  struct NFCReaderError
    省略

わからんわな。

NDEFは、TNFまでは見分けてくれるけど、あとは自分で解析してね、というスタンスのようだ。
なお、NDEFのフォーマットというのはこういう感じだ。

image

まあ、ほぼそのままを渡してくれるので、あとはこれからURIだのTEXTだのSmartPosterだのを自分で解析するのだろう。
自由度が高いが、まあ単なるデータだからね。。。

BLEのペアリングだったり、WiFiのSSIDなんかもタグで読めるだろうけど、iOSってアプリからそういう設定ってできなさそうな気がするから、ありがたみは薄いのかな。
コピー・ペーストができるなら、貼り付けるだけで済むようにできそうだけど、なんとなくそれも許してなさそうな気がする。

2017/06/07

[mbedTLS]マルチスレッドでは署名と検証は排他した方が良いのか?

全然そのつもりがなかったのだが、mbedTLSを使って作っていたライブラリをマルチスレッドで動かすことにした。
楕円曲線の署名して送信し、受信したら検証して別のデータをまた送信、というようなことを各スレッドで行うと思っておくれ。


ようやくベースができたので、手動でちょこちょこ通信させていたのだが、たまに検証に失敗することがある。
毎回ならロジックがどこかおかしいと思うのだが、たまに、なのだ。
まれに、というほどでもなく、比較的置きやすいのだが、少なくとも毎回ではない。

なんだ??


検証に失敗するからには、

  • 作った署名が間違っている
  • 署名の送信か受信が間違っている
  • 受信した署名までは正しいが検証で失敗している

のどれかなのだが、ログを出していてもどのスレッドが出しているのかうまく整理できず、何が悪いのかはっきりしない。。。
こういうときって、標準出力ではなく、せめてスレッドごとにログを吐くようにしておけばよいのだろうね。


mbedTLSのマルチスレッド動作については、ページがある。
Thread Safety and Multi Threading: concurrency issues - Knowledge Base - mbed TLS (Previously PolarSSL)

大ざっぱに読んで、MBEDTLS_THREADING_CとMBEDTLS_THREADING_PTHREADを有効にしたライブラリを作ればよいのだろう、と判断。
ただ、ecp.cにはTHREADINGのマクロがあるのだが、ecdsa.cの方にはない。
ヘッダを見ると、mbedtls_ecdsa_write_signature()は同じコンテキストだったらスレッドセーフじゃない、と書いてある。
ecp.cのmbedtls_ecp_mul()なんかもスレッドセーフじゃないというコメントが入っているが、こっちはmbedtls_mutex_lock()で排他しているのだ。

うーーん。。。。

中で呼んでいる関数のどこかで排他されているから大丈夫、というパターンかもしれないが、mbedtls_ecp_mul()なんかは「同じグループだとスレッド-セーフじゃない」といっているから、同じmbedtls_ecp_groupを使い回しているところが全体として危ないのかもしれん。
今回、mbedtls_ecp_groupは全員同じものを使っていいんじゃないの?と思い、開始時に設定したら解放せずに全員が同じものにアクセスするように作り込んでいたのだ。

その考え方自体が間違っているのかもしれんが、MBEDTLS_THREADING_Cなんて用意してあるくらいだから、そんなのしなくてもよいのかも。。。


わからんので、mbedtls_ecdsa_sign_det()やmbedtls_ecdsa_read_signature()は、mbedtls_mutex_lock/unlock()で囲むことにした。


そのおかげか、今のところ安定している。
でも、実はECDSAは直接関係なくて、その付近で使っている変数が問題だったり、あるいは単にタイミングが発生しにくくなっただけという可能性もある。


mbedtls_ecp_groupを共有していることの危険性が分かってないのよねぇ。
暗号化関係って、よくわからない計算をたくさんしているだけに見えてしまい、深く追いたくないのだ、そうもいっていられんのか。


2017/06/14

気になったので、mbedtls_ecp_keypair構造体の構成を見てみた。
mbedtls_ecp_groupではなくmbedtls_ecp_keypairなのは・・・ソースを見直すとkeypairの変数をグローバルで確保し、最初にloadして使い回していたからだ。

typedef struct
{
    mbedtls_ecp_group grp;      /*!<  Elliptic curve and base point     */
    mbedtls_mpi d;              /*!<  our secret value                  */
    mbedtls_ecp_point Q;        /*!<  our public value                  */
}
mbedtls_ecp_keypair;

あー、秘密鍵とか公開鍵をこの中で保持しているじゃないか!
こんな変数を使い回していたら、そりゃよろしくないですわな。。。
コメントにも「Members purposefully in the same order as struc mbedtls_ecdsa_context」となっているので、コンテキストが異なるスレッドからは使ってはいけない代物なのだ。


そういうわけで、毎回スタックでmbedtls_ecp_group_load()して使うようにした。
なんか、暗号化ライブラリって重たい処理をしていそうなので、使い回せるところは使い回した方がよいのではないかと考えてしまったのだ。
でも、それはそれでセキュリティ的によろしくないだろうから、考え直さないと。

[ios]Core NFC?

いつかなー、いつかなー、と思っていたiOSでのNFC APIだが、そろそろ使えるようだという話が出ている。

Apple adds support for NFC tags to iPhone 7 and Apple Watch • NFC World


APIはこちら。
まあ、実機を持ってないし、開発環境も無いので、見てみただけだ。

Core NFC | Apple Developer Documentation

Reading NFC NDEF tags is supported on iPhone 7 and iPhone 7 Plus.

だそうだ。


それはともかく、タイトルだけ見る限りはタグの検出とNDEFの読み出しができそうだ。

気になるのは「types 1 through 5」というところ。
えっ、いつの間にType5が出たの??

Type 5 Archives - NFC Forum | NFC Forum
あー、AndroidでいうところのNFC-Vか。


NFCは技術として好きなのだけど、NFC Forumが仕様書を会員以外には販売方式にしてから、どうにもやる気がなくなってしまった。
せめて、NDEFの仕様書とTypeの仕様書は公開してくれてもよいと思うのだが。。

2036年問題?

何気なく、2038年問題のことを調べていた。
正確にいえば、「2037年だっけ、2038年だっけ」を調べていたのだが、その途中で「2036年問題」というものを見つけた。


2036年問題とは - IT用語辞典 Weblio辞書

  • NTPは1900年1月1日を起点とした秒数で時間を表している
  • 範囲は、32桁の2進数
  • オーバーフローするのは、2036年2月6日0時54分54秒


あれ?
2038年問題の方を見てみよう。


2038年問題とは - IT用語辞典 Weblio辞書

  • UNIX環境では1970年1月1日0時0分0秒を起点とした秒数で時間を表している
  • 範囲は、31桁の2進数
  • オーバーフローするのは、2038年1月19日


ああ、符号付きかどうかの違いで70年近く差が出てくるのね。

マイナスになることもなさそうなのに、なぜ符号付きにしたのだろう?
当時の事情は知らないのだが、そういうコンピュータが多かったのかもしれん。


C言語だとtime_tで扱うのだけど、今は64bitになっているものが多いと思う。
もしかしたら、64bitのOSしか使っていないせいかも。
ただ、環境依存になることは仕方あるまい。

RTCなんかは割り切ってて、100年計測できるようになってるものが多かったように思うので、日付についてはアプリ管理だ。
昔はLinuxも32bitで扱ってて、どうせRTCチップ用にドライバ作るんだからということで、時計回りは別で扱うようになっていた。
便利なAPIは使えなくなってしまったのだけど、まあ、そういうのもありですな。


time_tの変数をポインタにして、uint32_tなんかでキャストし、またtime_tで直接ポインタから元に戻そうとすると変な値になってしまうから注意したまえ(2回くらいやらかした。。。)。

2017/06/06

[cortex-m]SWVとRTTは別物だろうか

How to perform runtime error checking on Cortex-M devices


ARM Cortex-MにはSerial Wire Viewerというリアルタイムイベントを拾うことができる機能があるらしい。
最近は組込みから遠のいているものの、手元にあるのはCortex-Mが載ったマイコンかESP8266くらいしかないので、デバッグ手段は知っておきたいものだ。
Hard Faultなんかが拾えるような感じで書かれているので、それができるならありがたい。



CoreSight
Keilでは、Serial Wire Serialの略がSWVになっている。何でだ?
ともかく、SWOピンを使うようだ。
SWOだから、Outputだろう。


ARM Information Center
ARMのサイトも見たが、これといった情報はない。
SWOとなんか命令がセットになって使えるようなもののようだ。


KeilのページではULINKなどしか載っていなかったが、ARMのしくみならJ-Linkでも使えるはずだ。
SEGGER - The Embedded Experts - J-Link Debug Probes - Software - J-Link SWO Viewer
こちらは、SWO Viewerというアプリ。
コードを足してやらんといかんようだが、SWOの出力を拾えるようだ。
Keilとかだったら、printf()で書けるのかもしれん(見てない)。


そうなると、RTTとの違いが気になる。
RTTはSEGGERのJ-Linkでしか使えなかったと思うが、nRFシリーズではソースが入っていたし、手っ取り早く使える。
SEGGER - The Embedded Experts - J-Link Debug Probes - Real Time Transfer
これもSWOを使うようだ。


SWVとRTTの違いはどういうところにあるのか探していると、Atollicさんのブログがあった。
Using the SEGGER Real-time terminal (RTT) interface with Atollic TrueSTUDIO
ぱっと見て気付いたのは、双方向ということと、パフォーマンスが高い、あとはJ-Linkで使える、というところか(RTTのページにも書いてあるが。。。)。
J-Linkのみという制限はあるが、上記の特典が得られる、という見方がよいのかな。

キーボードなどからの入力は試したことがないので、やってみたいところだが、用途が思いつかない。。。
ときどきログを出力させたいとか、全部ログに出すと重たすぎるので、分割させたいとかか?

[c/c++]たぶん構造体メンバをvolatileにしても有効(弱気)

タイトルが弱気だが、致し方ない。


何がしたかったかというと、pthread_create()で動かしているスレッドでwhile()させてぐるぐる動かしている状態を、外部から止めたかったのだ。

スレッドで、whileで、変数監視となると、volatileになる。
普段はグローバル変数で監視させていたのだが、今回はスレッドをぽこぽこ作るようにしていたので、各スレッドが使う変数を構造体でまとめて初期値で与えつつ、そのままスレッドと共有する領域として使おうという計画だ。
おじさんはね、OSを使ったプログラムに慣れていないので、他に方法が思いつかなかったのだ。


その構造体の中に、ループを制御するための変数を持とうと思ったが、ちょっと迷った。
volatileって、構造体のメンバに指定しても反映してくれるのだろうか?


こういうときは、環境依存になってもよいから実験するに限る。


#include <stdio.h>

struct vol {
    int     abc;
    volatile int     def;
} volvol;


int main(void)
{
    while (volvol.def) {
        ;
    }
    return 0;
}

$ gcc --version
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

こんな環境で試した。
なお、Ubuntuは16.04で、VirtualBox上で動かしている。
コンパイルはこのようにして、O2で最適化してアセンブラ出力させた。

$ gcc -O2 -o vol.S -S vol.c


まず、volatileありの場合。

	.file	"vol.c"
	.section	.text.unlikely,"ax",@progbits
.LCOLDB0:
	.section	.text.startup,"ax",@progbits
.LHOTB0:
	.p2align 4,,15
	.globl	main
	.type	main, @function
main:
.LFB23:
	.cfi_startproc
	.p2align 4,,10
	.p2align 3
.L2:
	movl	volvol+4(%rip), %eax
	testl	%eax, %eax
	jne	.L2
	rep ret
	.cfi_endproc
.LFE23:
	.size	main, .-main
	.section	.text.unlikely
.LCOLDE0:
	.section	.text.startup
.LHOTE0:
	.comm	volvol,8,8
	.ident	"GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609"
	.section	.note.GNU-stack,"",@progbits

ふーん。

次、volatile無しの場合。

	.file	"vol.c"
	.section	.text.unlikely,"ax",@progbits
.LCOLDB0:
	.section	.text.startup,"ax",@progbits
.LHOTB0:
	.p2align 4,,15
	.globl	main
	.type	main, @function
main:
.LFB23:
	.cfi_startproc
	movl	volvol+4(%rip), %eax
	.p2align 4,,10
	.p2align 3
.L2:
	testl	%eax, %eax
	jne	.L2
	rep ret
	.cfi_endproc
.LFE23:
	.size	main, .-main
	.section	.text.unlikely
.LCOLDE0:
	.section	.text.startup
.LHOTE0:
	.comm	volvol,8,8
	.ident	"GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609"
	.section	.note.GNU-stack,"",@progbits


差分は、ここ。
左がvolatileありで、右がvolatileなしだ。

image

L2ラベルでループしていて、volatileありはmovlがループ内に、volatile無しはmovlがループ外になった。

効いてる! 効いてるんだ!!


まあ、そもそもなんでvolatileが効かないかもしれないと思ったのか、という気もしてくる。
単に不安になっただけだ。
そういうことってあるだろう?


そういえば、gccとかって中間言語に吐き出してからリンカに掛けるとかだったから、アセンブラで安心するのは早いかもしれん。。。
いや、さすがにそこまでは疑わなくてもよいか。

2017/06/02

[bc]スクリプト

たまにはBitcoinの記事も書いておかねば。
べ、別にネタに困ってるわけじゃないんだからね!


Bitcoinのブロックチェーンに載せるデータは、トランザクションが最小単位になる。
メッセージとしてはping/pongやgetdataなどいろいろとあるのだが、ブロックチェーンに載るものとしてはtxメッセージで送信するトランザクションが基本になるだろう。

トランザクションには、だいたいこういうデータが載っている。

    • トランザクションのバージョン
    • 送金元の情報
    • 送金先の情報
    • どのくらい待ってからマイニングできるようになるか


「送金元の情報」は、その前のトランザクションの「送金先の情報」とつながっている。
この意味に慣れるまで、私はけっこう時間がかかった。。。

銀行の送金だと、送金元が「いくら、誰誰に送金する」と指定して、送金先の人にその額が入る。
Bitcoinの場合、送金元が「いくらは誰誰に送金し、残りはこれこれに送金する」という記載の仕方をする。
例えば、誰かに0.1BTC送金する必要があったとしよう。
そして手元に1BTC使えるトランザクションを持っていたとする。
そうすると、

  • 0.1BTCを送金したい人に
  • 残りの0.9BTCを自分のお釣りに

という送金の仕方になる。

お釣りを、送金元と同じアドレスに指定することもできるのだが、セキュリティ的には推奨されない。
だから、だいたいは見た目として2つのアドレスに送金しているように見える。
初めてトランザクションを見たときには「なんで全部送らないといけないのよぉぉ」と思ったものだ。

そしてまた、トランザクションを作るときには手数料(FEE)がかかる。
先ほど0.1BTC + 0.9BTCのような書き方をしたが、実際にはこれにFEEが引かれて、0.89999BTCみたいな額になっていることだろう。

FEEの決め方はよくわかっていないが、トランザクションのバイト数が基準になっている。


で、スクリプトだ。

BitcoinにはEthereumほどの柔軟性はないにしても、スクリプトを書いて送金条件を作ることができる。
逆ポーランド記法というか、スタックにためながら演算していくのだ。


その演算は、大ざっぱに言えば、「前のトランザクションの送金先情報」と「それを送金元として使うトランザクションの送金元情報」がセットになって解くことができるスクリプトになっている。
私のイメージとしては、昔のウェスタンな取引で、お札をギザギザに破って取引相手に渡しておき、現場でそのギザギザがお互いに一致するかどうかで見分けるアレだ。


今のところ、この辺が使えるようである。
Script - Bitcoin Wiki

「今のところ」がつくのは、Bitcoinがトランザクションのバージョンによって使えるスクリプトが変わるからである。
例えば、NOP2やNOP3のような命令が、バージョン2ではOP_CLTVやらOP_CSVとして使えたりする。
Script - Bitcoin Wiki - Locktime


こういう、意味の使い方が変えられるという自由さが、仮想通貨のよいところだったり悪いところだったりするのだろう。

2017/06/01

[c/c++]キャストで逃げる

コーディングするたびに発生して、毎回悩むのに答が出ない問題がいろいろある。

キャストで逃げるというのも、まだ私の中で解決していない。
たとえば、ポインタとサイズをセットにした構造体を作ったとしよう。

struct xxx {
  int len;
  uint8_t *ptr;
};

C言語だと、アドレスは分かってもサイズが分からないからね。


malloc()などでRAMを使う場合はこれでもよいのだが、const値のようにROMで持っているデータを使いたいとなると悩んでしまう。
ptrはconstが付いていないため、書き換え可能なように見えてしまうからだ。
構造体のインスタンスにconstを付けても、lenやptr自体は書き換えできないが、ptrが指す先はconstではないからね。
(最近もこういう話をどこかで書いたな。。。)


今回は、こうやって回避した。

struct const_xxx {
  int len;
  const uint8_t *ptr;
};

constになっている型をもう1つ用意したのだ。
これがあれば、RAMであっても書き換えるつもりがないことを表すこともできるし、大丈夫だ!


と思っていたのだが、また揺らぎだした。

これ、ポインタがプリミティブ型だからよいようなものの、構造体だったらどうだろうか?
その構造体の中にポインタが入っていて、それがconst無しだったら強制力がないだろう。

だったらもう、constにした構造体の中身は下の方に至るまで書き換えるなよ?とした方が潔くないだろうか。
証明するのは大変だが、テストコードで書き換え不可のアドレスを渡して不正メモリアクセスなどの例外が発生しないことを確認するくらいしかないか。

これにconstのアドレスを渡したい場合は、そのまま渡すとwarningが出るので、const外しキャストで逃げることになろう。
格好はよくないのだけど、他に方法が思いつかない。
warningのままにして気付かせるようにしておくのもありだが、warningをerror扱いにしたいこともあるし、何よりうっとうしい。
const_cast<>がないので検索もしづらいのだ。


うーん、いろいろめんどうだ。
何かC言語仕様の見落としがあるかなぁ。。。

2017/05/31

[c/c++]lmdbのmstest.cサンプル

lmdbのmtest.cサンプルにコメントを入れてみた。
見えるかしら?

lmdbのmtest.c

コメントを入れた目的は、何やってるか知るため。
ドキュメントを見てもAPIが多いので、全部読むよりサンプルを眺めた方が早いと思ったのだ。

[c/c++]lmdbをマルチスレッドで使いたい

lmdbで、同じDB(といえばよいのか?)をマルチスレッドで使おうと思っている。
まあ、DBというくらいだから、ロックなんかは自動的にやってくれるだろうと何も考えていなかったのだが、なんだかうまくいっていない。


テスト用だからとエラーチェックをしていなかったので、どこでエラーを出しているか確認用のサンプルを作った。
lmdb multithread open fail

スレッド関数でトランザクションまで開いた後スリープし、その間に別スレッドで同じことを行うだけだ。
どこでエラーになったかというと、openだった。

fail: mdb_env_open(2)=16(Device or resource busy)

うーん、mdb_env_open()はEBUSYを返さないのかと思ったが、そうでもないようだ。


mdb.cを見ると、mdb_env_map()でEBUSYを返す箇所があるから、mdb_env_open()の引数でMDB_FIXEDMAPを使っているせいかもしれない。
言い訳になるが、lmdbのサンプルソースがMDB_FIXEDMAPしか使っていないから、それがデフォルトだと思ったのだよ。。。



そもそも、LMDBにとってマルチスレッドはどういう扱いなのだろうか?

LMDB: Lightning Memory-Mapped Database Manager (LMDB)

ロックファイルを使うからどうのこうの、と書かれている。
それ以外の基本的な考え方としては、

  • A thread can only use one transaction at a time, plus any child transactions.

ということで、トランザクションの間は1つしかアクセスできないようだ。
これがlmdb内でやってくれるのか、外側でそうしないといかんのか。。。


ああ、今回のエラーについては、その次に書いてあった。

  • Use an MDB_env* in the process which opened it, without fork()ing.
  • Do not have open an LMDB database twice in the same process at the same time.

まず、mdb_env系のAPIはopenしたプロセスで使用しなさい、とのこと。
それ以外のAPIだったらfork先でも使ってよいということかな?

また、openは2回するな、と。
今回はこっちでエラーになったのかな?

試しに、MDB_FIXEDMAPフラグを外して実行してみると・・・エラーが出なくなった。
トランザクションでエラーになるかと思ったが、そうでもなかった。
これはbeginさせているだけだからかも。


どこかにまとめて書かれていないものか探したら、Getting Startedページにあった。
LMDB: Getting Started

  • LMDBはPOSIX lockを使う
    • このlockは、1つのプロセスで複数回ファイルを開くと問題がある
    • だから、mdb_env_open()は1つのプロセスで複数回実行するな
      • その代わり、スレッド間でLMDB environmentを共有しなさい
      • そうせんかったら、複数openした箇所のどこかがcloseするとロックが削除されてしまう
  • transactionは、デフォルトでTLS(thread local storage)に入っている
    • read-onlyなtransactionでよいなら、MDB_NOTLSオプションを使ってもよいよ


そんなわけで、LMDBとしてはmdb_env_open()を複数回呼んではいかんのだけど、今回発生したエラーはそれが原因ではなかったし、複数回呼んだからといってエラーになるというわけでもないことが分かった。

2017/05/28

[c/c++]lmdb

以前、Caffeを見ていたときにlmdbのデータを見る方法を調べたことがある。
http://hiro99ma.blogspot.com/2015/10/caffelmdb.html

このときは、mdb_dumpというツールでデータを見るだけだった。


そして、Cで書かれているKey-Value StoreなDBがないか探していると、lightning memory-mapped databaseなるものが出てきた。
OpenLDAPプロジェクトで作ってるようなのだが、これがlmdbだったのだ。

Symas Lightning Memory-mapped Database | Symas Corporation

世の中、狭いねぇ。


github(ぎっとはぶ、と読むのだね。私は、じっとはぶ、と読んでて怪訝な顔をされたよ)はこちら。
https://github.com/LMDB/lmdb


makeすると、ライブラリなどが生成されていた。
単独でビルドできるか、別の場所に「lmdb.h, liblmdb.a, mtest.c」だけをコピーした。

$ gcc -o tst mtest.c -L. -llmdb -pthread

うん、ビルドできた。

$ ./tst

あ、あれ、死んでしまう。。。
なんだ、dbを置くディレクトリは自分で作らんといかんのか。

$ mkdir testdb
$ ./tst

結果は分からないが、動いた。



lmdbを見つけるより前に、FineDBというものを見つけていた。
FineDB

これがlmdbをベースにしている、と書いていて、そういえばlmdbって記事にしたことあるな、という経緯でたどり着いたのだった。


FineDBはまだ動かしていないが、フォルダ構成がserver/cliとなっていて、これはこれで面白そうだ。
ただ、4年前が最後のcommitなので、lmdbを参照にしている部分は古いのかもね。

2017/05/27

[c/c++]leveldbをcで使いたかったが、libstdc++が必要だった

いつもsqliteを使っていたので、たまには違うものを使っておこうと思い、leveldbを使ってみることにした。

google/leveldb: LevelDB is a fast key-value storage library written at Google that provides an ordered mapping from string keys to string values.


configureなどがないので、makeして、includeディレクトリと、out-staticに入っていたlibleveldb.aを別の場所にコピーして、emnl/leveldb-c-exampleからleveldb_example.cを持ってきた。

$ gcc -I./include -o tst leveldb_example.c -L. -lleveldb -pthread

・・・大量にリンクエラーが出てきた。
deleteがどうのこうのと出ているので、C++のライブラリがいるようだ。
まあ、もとがC++だから、仕方ないか。。。


しかし、snappyとかいうエラーも出ている。
データを圧縮するライブラリらしいが、必須なのか?

Makefileを見ていくと、どうやらbuild_detect_platformというスクリプトで環境をチェックして、設定をbuild_config.mkに作り、それをMakefileが読込んでいるようだ。
どうやら、私が使っている環境ではsnappyをapt-getか何かでインストール済みのようだ(実を言えば、leveldbもインストール済みだった)。
今回は最小構成にしたいので、スクリプトでsnappy検出のところをコメントアウトさせた。


これでもlibstdc++.aみたいなものはいるので、あきらめよう。

$ gcc -I./include -c leveldb_example.c
$ gcc -o tst leveldb_example.o -L. -lleveldb -pthread -lstdc++

動くようだ。


サンプルが、leveldb_put()するときに"value"という文字を書き込んでいるのだが、きっちり5byte分しか書込んでいないので、その後でleveldb_get()したあとにprintf()したときの文字が化けて出力されることがあるようなので、気になる人は\0まで書込むなり、get後に\0を足すなりするとよかろう。

Cだけで書かれたNoSQLというかKVSのライブラリがあると、小さそうでよいのだけどね。

2017/05/26

[linux]msgsnd()のサイズを計算したい

まだやっている、Linuxのメッセージキューの調査。

前回で終わりの予定だったが、msgsnd()のmsgszを自動で計算したくなったのだ。
mtext[SZ_BUF]みたいにサイズが決まっているならやりやすいけど、メッセージキューってデータ構造を問わないので、せっかくなら使うデータをずらずら並べたいところだ。
そうすると、msgszがよくわからなくなってしまう。


試しに、msgszを8192にしたまま、構造体のサイズを小さくしてみた。
うん、やっぱりcoreを吐いてしまう。
msgrcv()だけが死ぬときもあれば、msgsnd()が死んでしまうこともある。
アラインメントによっては、死なないこともありそうだから、サイズはやはり気をつけておきたい。


あれこれ考えたが、これくらいしか思いつかない。

  • 構造体のsizeofから、mtypeの次のメンバーをoffsetof()した値を引く
  • mtypeの次のメンバーを構造体にしてしまう

後者の方がスマートかな?

2017/05/25

[linux]msgsnd()のサイズ確認

前々回の記事だが、タイトルは間違っていないものの、検討結果が間違っていた。
修正したので、以前読まれた方は申し訳ないが、一番下だけでも再確認していただきたい。

[linux]メッセージキューのmsgszは8192を超えてはいかん

msgsnd()のサイズ指定を構造体全体のsizeofでやっていたのだけど、指定するのはmtextの部分だけのようだ、ということだ。



が、すっきりしないので検証を行った。
Xubuntu16.04だ。

https://gist.github.com/hirokuma/5916e918f40bbf82dc5723e42789007c

まず、構造体としてはmtextを8192より256くらい多めに確保する。
送信側はmtextをすべて0x77で初期化し、受信側は0xccで初期化しておく。
そしてmsgsnd()では8192を指定し、受信側のmtextが0x77以外になるポイントを探す。


結果としては、8192、と出力された。
0から始まるので、0~8191までの8192バイトは0x77であることが確認できた。

sizeof(構造体) - sizeof(long)としているサイトがあったので、8192がどこからどこまでなのかが気になっていたのだ。
もしsizeof(long)が開始地点だったら、8188バイトまでしかコピーされていなかったはずだ。
一応offsetof()で調べたが、mtextは8バイト目だった。


よし、これでもう間違えないぞ。

[clang]BUFSIZ

マクロにBUFSIZというものがあったのだが、なんだろうか?
stdio.hに入っていることは分かったのだが・・・。



これは、ファイルが使用するI/Oバッファサイズに関係するようだ。
Man page of SETBUF
setbuf()がBUFSIZを使い、setbuffer()はそのサイズ指定可能版ということか。


printfさせると、BUFSIZは8192だった。
環境や時代で変わる値だと思うが、8KBまではバッファリングされることになる。


Man pageの説明を読むと、意識していないことが書かれていた。

  • バッファリングの種類は3種類ある
    • unbuffered
      • 出力をすぐ書込む
    • block buffered
      • 文字の読み書きはブロック単位で行われる
      • 吐き出すにはfflushなどを使う
    • line buffered
      • 新しい行が出力されるか、新しい行が入力されるまでためられる
  • ファイルはすべてblock buffered
    • 初めて入出力するときにmallocが呼ばれる
  • stderrはunbuffered


printf()とfprintf(stderr)を混ぜていると、出力されるタイミングが違うなあ、と思っていたのだ。
出力先が違うからだと思っていたが、バッファリングの種類が違っていたからなのか。


引数がFILE*だから、システムコールレベルではなく、stdioとしてサポートしていることになるのだな。
open()した場合は、OSの動作を見ておかねばなるまい。

[linux]メッセージキューのmsgszは8192を超えてはいかん

※2017/05/25 22:25 修正あり

Linuxのメッセージキューは、まずはサンプルを動かすことにした。
いつものように、LinuxといいつつWindows10のBash on Ubuntu on Windows(以下 BoW)だ。

が・・・コンパイルは通るものの、msgget()でエラーになる。

Function not implemented


嫌な予感は的中した。
System V IPC is missing · Issue #1016 · Microsoft/BashOnWindows

Creators Updateでセマフォと共有メモリは対応したけど、メッセージキューはbacklogと書いてあるから、まだ残ってるという意味なのかな。


まあ、何でもかんでも期待しちゃいかんだろう。


VMに入っているUbuntu環境に持っていくと、進んだ。

が、msgsnd()でInvalid argumentが出てしまう。
Man page of MSGOP
msgsnd()がEINVALを返すのは、以下のどれか。

  1. msqid が不適切な値
  2. mtype が正の値でない
  3. msgsz が不適切な値 (0 以下か、システムで決まる値 MSGMAX よりも大きい値)

msqidはチェックしているし、mtypeも正の値を代入している。
ということは、3番のmsgszだ。

サンプルでは、こういう構造体になっていた。

struct {
    long mtype
    char mtext[BUFSIZ];
};

このBUFSIZは、8192だった。
だから、sizeofすると、たぶん8196・・・違った、8200だった。
8byteアラインなのね。


ではMSGMAXは?
これはマクロ値にはなっていないようだったが、Man pageの下の方に書いてあった。

MSGMAX

メッセージのテキストの最大サイズ: 8192 バイト (Linux では、この制限値は /proc/sys/kernel/msgmax 経由で読み出したり変更したりできる)。

うーん、ここだけ読むとメッセージのテキストの最大サイズだから使ってもよさそうなのだけど、msgszのが超えたらいかんと書いてある方が強いのだろう。


というわけで、うちの環境ではmtextが8184までOKで、8185からInvalid argumentになった。

sizeofはマクロに入れられないので、

struct {
  long mtype;
  char mtext[SZ_BUF];
};

#if 8 + SZ_BUF > 8182
#error !!!
#endif

みたいにして判定させるのが良いかも。


※追記

あれからいくつか見てみたが、msgsnd()に指定するサイズとして、sizeof(構造体)ではなく、sizeof(構造体) - sizeof(long)、としているサイトが見られた。
ま、まさか・・・。

もう一度説明を見直すと、msgsnd()のサイズとして指定するのは、struct msgbufではなく、mtextに相当するサイズ(msgsz)と書いてあるではないか!

私はmsgsnd()で構造体のサイズを指定していたのだが、それではダメだ。
そして、アラインメントもあるので、sizeof(long)を引くのも正しくなさそうな感じがする。
ここは、mtextに相当するサイズをマクロで指定するのがよいのかもしれん。


ふっ、まだまだ私も青いのぅ。。。
タイトルは間違っていないものの、動作検証をしていないから、後日やろう。

2017/05/24

[c/c++][linux]プロセス間でのメッセージキューに似たものはあるのか?

久々に、Linuxでネットワーク関係のアプリを書こうとしている。

やりたいのは、裏で通信してくれるアプリと、そのアプリに指示を出すアプリだ。
うまく作れば1つのアプリにまとめてもよさそうだが、いかんせん、コンソールから指示を入力させたりする実装をしたくないので、別アプリにして引数で指示を与えようと考えたのだ。
これもRPCの一種になるのかな?


そこまで考えて、悩むことになった。
どうやって指示アプリと通信アプリを接続すればよいのだろうか?
確かローカル環境では、socketpairでファイルみたいなのを作ってやっていたような気がする。。
まあ、今回は指示を出すだけなので、pairは作らなくてよいか。


指示を出すだけなので排他処理はいらないように見えるが、裏で通信していて、受信したメッセージによっては送信を行うことがある。
その送信も、指示するのと同じ経路でやってしまおうと考えている。
つまり、送信処理をキューでためられるようにして、そのキューには指示アプリか受信メッセージが追加を行う。
それぞれプロセスが違うので、ここに排他処理を入れようというわけだ。


なんとなく、共有メモリを作って、セマフォで排他するんじゃなかろうか、と思ったのだが、メッセージキューがあるらしい。
msegrcv, msgsndには排他がいるとか書いていないから、排他は不要なのかな?


しかし、メッセージキューに関して検索しても、あまり新しい記事が出てこない。
実はもっと便利なライブラリがあったりするのでは?と探すが、うまく探し出せない。
関連する語彙がわからん。。。


わからんので、ここら辺を見ながら作ってみよう。
IPC: Message Queues | Shinta's Site

[c/c++]accept数を制限したい

珍しくsocketで作っている。
serverという程のものではないのだが、socketをいくつか受け入れるしくみを作ろうとしている。

Man page of LISTEN

socket()して、bind()して、listen()して、あとはaccept()でやってくるのを待つ。
教科書通りにやると、accept()で処理がブロックされて、clientからのconnect()を待つことになる。

 

今回は、同時にN個まで接続できる、というようなことをやりたい。

socketって、同じポートで接続できないんじゃなかったっけ?と思ったが、connect()する方が適当にポート番号を振って接続しに来るためか、あまり気にしなくてよかった。
まあ、次々accept()したいから、スレッド起動させたりはせんといかんが、そのくらいのようだ。

では、あとは数を制限するだけだ。
・・・・あれ、どうやって?


今回も、Windows10のBash on Ubuntu on Windowsでやっている。

まずは、一番それっぽいように見えた、listen()のbacklogを変更した。
接続キューの上限みたいだから、それでいけると思ったのだが・・・ダメだ。
よく読むと「保留中の接続のキューの最大長」とのことだ。
だから、手でconnectするアプリを次々起動させるようなことでは、保留させる必要がないということだろう。

 

linux - Is it possible to unlisten on a socket? - Stack Overflow
これを読むと、accept()してすぐclose()!らしい。

int delsock = accept(sock, NULL, NULL);
close(delsock);

まあ、確かにやりたいことは満たすのだけど、connect()でエラーが返るわけでは無いので、ちょっとなぁ。

 

しかし、connect()のエラー値を見ても、あまりふさわしいのがないな。
ECONNREFUSEDが近いけど、ちょっと意味が違う。
一時的にリソースが使えない、みたいなのはなさそうだから、あんまりがんばっても仕方ないのか。

2017/05/23

[win]WinMerge

Windows10で、ファイルの比較をするのにWinMergeを使っている。
version 2.14.0.99+-jp-99となっているから、日本語版なのかな。

image

 

シェル連携させていて、Explorerのファイルを選択してコンテキストメニューから「比較」とすると、比較した画面が表示されるので便利だ。

image

 

何気なくファイルを選択してしまうと、左右のどちらにどのファイルがいるのかわからなくなってしまうのだが、選択の仕方を意識的に行うだけで、どちらにどのファイルが来るのか確定できそうな気配だ。

「気配」としたのは、今のところ私の環境はそうなっているけど、何でそうなるのか知らないからで、他の環境だとそうならないかもしれん。

 

私の環境では、2ファイルを選択する場合、ExplorerからCtrlキーを押したままファイル選択を1つずつ行うと、比較ウィンドウの右側に1番目に選んだファイルが、左側に2番目に選んだファイルが出てくるようだった。
ファイルがソートされている順に左→右と出したいのであれば、Explorerでは並んだファイルの下からCtrlキーでクリックしていくと期待通りに出てくれている。

 

技というほどではないし、確定しているものでも無いけど、私の場合はこれでずいぶんと手間が省けるようになった。

2017/05/21

Diffie-Hellmanの25519や448とは?

前回、まったく内容を理解しないまま、noise-cのサンプルアプリだけ動かした。
あとは、これをプロジェクトに組み込めばよい・・・と思っていたのだが、そうではなかった。
まだわかっていないが、サンプルも引数で設定が変更できたように、何か使用方法を決めるというもののようだった。

 

たとえば、Noise_NN_25519_AESGCM_SHA256、などという名前が、何か意味を持っているらしい。

Prefix : Noise
Pattern : NN
Diffie-Hellman : 25519
Cipher : AESGCM
Hash : SHA256

ということのようだ。
もはや呪文ですな。。。

 

noise-cがサポートしているアルゴリズムは、ドキュメントに書かれている。
http://rweather.github.io/noise-c/index.html#algorithms

これが仕様を満たしているのかどうか、満たしていなかったら改造できるのかどうか、改造できなかったら他のライブラリがあるのかどうか、その辺を見ていくことになりそうだ。
うう、つらい・・・。

つらいのだが、誰か調べてくれるわけでもないので、基礎知識に相当するものくらいは記事にしてもよかろう。


知りたいのは、Diffie-Hellmanだ。
サンプルのechoでも、25519と448という数字しか出てきていない。
そもそも、Diffie-Hellmanって鍵交換とかそういうはなしじゃなかっただろうか?
それの数字って、何なのだろう。

 

RFC 7748 - Elliptic Curves for Security
検索すると、すぐに出てきた。
RFCで推奨している楕円曲線の種類が、25519と448という名前のようだ。
RFC 7748だけじゃなくて、8031や8037などにも出てくるな。

2^255 - 19をつなげて、25519。
448はちょっと違って、2^448 - 2^224 - 1となっている。
そういえば、前調べたChaCha20-Poly1305も、2^130 - 5だったからそういう名前だった。


Diffie-Hellmanは、安全に鍵を交換するための方式だ。
鍵といっても物理的な鍵ではなく、データとしての鍵だ。
検索すると、たくさん出てくる。

また、CipherやHashも暗号関係の技術だ。
これらをどう組み合わせてもよいようにできているのだろう。

だから・・・noise-cが対応していないパラメータを使うようになっているという可能性もあるということだ。
嫌な予感はするのだが、これ以上は触れるのを止めておこう。

[c/c++]noise-c ?

仕様書で「プロトコルはnoise-cで」みたいなことが書かれていた。

noise-c ???

どうやら、Noiseプロトコル、というものがあるらしく、そのC言語実装がnoise-cだそうな。
rweather/noise-c: Noise-C, a plain C implementation of the Noise protocol

プロトコルに興味は無いのだが、githubに上がってるくらいだから、ブログのネタにしても悪くはなかろう。


プロトコル仕様は、これらしい。

The Noise Protocol Framework

いやー、見る気にならんわー。
最初の方に"crypto"と出てくるので、何か暗号化するようなプロトコルなのだろう。

こういうのって、作っている人は改良しながらやっていくから中身が分かるのだろうけど、外側から見ている人、特に私みたいに成果だけ使おうとしている人にとっては、なかなかつらい。

私もgithubにときどき上げているが、使いやすくがんばっているわけではないし、そもそも「誰にでも使えるように」などと考えているわけではないから、同類だ。
それに、ドキュメントを整備しているわけではないから、同類とすることすらためらわれるレベルである。。。

 

まあ、いいのだ。
使おうと思う人が増えると、自然とドキュメントも整備したくなってくるものだから、それだけの違いなのである。


話を戻そう。

noise-cの使い方はまだわからないが、examplesはある。
Noise-C: Using Noise-C: Client/Server Echo Example

ただ、これを読んだまま実行してもなんだかわからなかったので、手順を残しておこう。
動かしたのは、bash on ubuntu on windows(16.04)だ。

 

 

githubから落とす

cloneでも何でもよいので、持ってこよう。

 

makeする

autogen.shがあるから、まずはそれを実行するとよかろう。
Build手順が載っているので、その順番でよいのではなかろうか。
Noise-C: Main Page

 

exam:key生成

いま、noise-cのディレクトリにいるとしよう。

$ cd examples/echo
$ mkdir keys
$ cd keys
$ ../echo-keygen/echo-keygen 25519 client_key_25519 client_key_25519.pub
$ ../echo-keygen/echo-keygen 25519 server_key_25519 server_key_25519.pub
$ ../echo-keygen/echo-keygen 448 client_key_448 client_key_448.pub
$ ../echo-keygen/echo-keygen 448 server_key_448 server_key_448.pub

パスをちゃんと書けよ!と思った。

実際は、*.pubの方を公開するのだけど、今回は同じPC内で実行するから、面倒を省くために keys/に全部置いているだけだ。
psk(pre-shared key)もいるらしいが、読んでもよくわからんので、こういうスクリプトを作った。

#!/bin/bash
rm -rf keys
mkdir keys
./echo-keygen/echo-keygen 25519 keys/client_key_25519 keys/client_key_25519.pub
./echo-keygen/echo-keygen 25519 keys/server_key_25519 keys/server_key_25519.pub
./echo-keygen/echo-keygen 448 keys/client_key_448 keys/client_key_448.pub
./echo-keygen/echo-keygen 448 keys/server_key_448 keys/server_key_448.pub

echo -en '\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f' > keys/psk.bin
base64 keys/psk.bin > keys/psk

 

exam:server起動

待ち受ける方。

$ cd examples/echo/echo-server
$ ./echo-server --key-dir=../keys 7000

これで、待ち状態になった。

 

exam:client起動

serverに接続をお願いする方。

$ cd examples/echo/echo-client
$ ./echo-client Noise_NN_25519_AESGCM_SHA256 localhost 7000
Noise_NN_25519_AESGCM_SHA256 handshake complete.  Enter text to be echoed ...

これで待ち状態になった。
なにかテキストを打ち込むと、そのまま返ってきた。

hiro99ma
Received: hiro99ma

うーん。。。動いているような気はするが、そもそもなんだかわかっていないので、そこから先に進めないな。
こうやって、詳細を調べていく間に世の中が進んでいくのだけど、まあ仕方ないわね。。。


examplesには続きがあった。
上記の動かし方は、static keyが不要な動かし方らしい。
確かに、作ったkeyを指定してない。

$ ./echo-client --client-private-key=../keys/client_key_448 \
            --server-public-key=../keys/server_key_448.pub \
            Noise_KK_448_ChaChaPoly_BLAKE2b hostname 7000

これを実行すると、echo-server側にエラーが表示される。

set client public key: Unknown identifier

ソースでいえば、ここのはず。
コメントからすると、client用のpubkeyを設定しているのだろう。

 

・・・ここのif文って、どっちもNOISE_DH_CURVE25519しかチェックしてないじゃないか。。。
NOISE_DH_CURVE448に変更すると動いた。

修正されたので、もう大丈夫だ。

2017/05/19

[win]Bash on Ubuntu on Windows起動

2017年4月のCreators Updateを当てたWindows10を使っている。
Bash on Ubuntu on Windows(な、長い。。。)の安定度が増したので、非常にありがたい。
デフォルトがこっちになって、コマンドプロンプトエミュレーション機能、みたいな形になっても困らないくらいだ。

起動するときは、メニューからショートカット選択している。
プロパティは、こう。

image

テキストエディタで編集しているディレクトリで開いてくれるとありがたいのだが、このbash.exeは特殊なためか、私が使っているEmEditorでは起動に失敗してしまう。

image


話が少し変わるが、最近テキストエディタとしてVisual Studio Codeを使うようになってきた。
自分で書いたくらいのC言語だったらテキストエディタでも追えるのだが、あまり使わない言語だったり大きいプロジェクトだったりすると関数を探すだけで疲れてしまう。

Windows上でVisual Studio Codeを起動しているのだが、Ctrl+@で「端末の切り替え」というキーに割り当てられているようだった。
なんとなく押すと、PowerShellが起動した。
「もしかしたら、bashが起動できるのでは?」と見てみると、できるようになっていた。
VSCodeをフォルダで開いているためか、bashもそのディレクトリで起動している。

 

さすがMicrosoft製だけあって、自分のところからは起動できるのか、と設定を見てみると、こういうのが追加されていた。

"terminal.integrated.shell.windows": "C:\\WINDOWS\\Sysnative\\bash.exe"

\WINDOWS\Sysnative?

image

ないよなぁ。。。

が、このパスをEmEditorに指定すると、bashが起動した。
へー。
もう試す環境が無いのだが、Anniversary Updateでも使えたのかもしれん。


おまけ

VSCode ver.1.12.2を使ってるけど、検索のデフォルト設定方法がわからん。
起動すると「大文字小文字の区別無し」「単語検索ではない」になっているのだけど、私は通常がその逆なので、毎回設定し直さないといけない。
設定方法があったら教えてくだされ。

 

大文字小文字を区別しなかったら、思ってもないものが検索されて困りそうだけど、他のエディタでもデフォルトがそうなっているから、少数派なのか。。。

2017/05/18

[c/c++]leveldb ?

ちょっとしたデータを読み書きして保持するとき、SQLiteと使うことが多かった。
別に検索したいとか、そういう要望があるわけではなく、他にそういうものはないのだろうと思い込んでいたのだ。

 

最近、またそういうデータを保持するしくみがいるので、どうしたものか悩んでいたら、leveldbというものがあることを教えてもらった。

グーグルがNoSQL軽量ライブラリ「LevelDB」をオープンソース化。SQLiteとの比較ベンチマークも公開 - Publickey

NoSQLですか。。。
まずはその用語からですな。


NoSQL - Wikipedia

"RDBMS以外のデータベース管理システム"くらいの言葉らしい。
リレーショナルデータベースマネージメントシステム、かな。
テーブル書いて、線でつなげていた気がする。

 

leveldbは、リレーショナルじゃなくて、キーバリュー型。
キーとそれに対するバリューをストアするので、キーバリューストアとか、KVSとか呼ばれるようだ。
そういえばAndroidのプリファレンスもそのくらいの機能しか使わなかったな。


google/leveldb - github

C++か。。。
c.hという、Cのインターフェースがあるので、ライブラリを作ってしまえばCからもアクセスできそうだ。

ただ、APIが思ったよりも多いので、ROMが多少心配だ。
また、できればファイルシステムを使わないようなところでも使えるとよいのだが・・・さすがに無理か。

2017/05/17

[c/c++]またMakefileの名前一致で失敗していた

以前、こういう記事を書いた。
hiro99ma blog: [c/c++]Makefileのdependは名前一致なのか

依存ファイルのオブジェクトファイル部分に相対のパス名が入っていると、うまくいかないようだった、という話だ。
相対というのは、

obj/./test.o

みたいに、間違ってないけど不要な相対パスなのかもしれん。
そこまでは調べていないのだ。

 

そのあと、依存ファイルの作り方を変更することで対応できそうだったという記事を書いた。
hiro99ma blog: [c/c++][make]dependの解決

そのMakefileを使っていたのだが、またうまくいっていなかった。
オブジェクトファイル名をソースファイル名から作っているところで、単にフォルダ名と拡張子だけを変更していたのだが、ソースファイルをさらに別ディレクトリを作っているとダメだったのだ。

 

こんなディレクトリ構成になっている。

_build/
   hello.o
   hello2.o

src/
  hello.c
  hello2/
    hello2.c

だが、ソースファイルをそのままオブジェクト名にしてしまうと、

_build/hello.o
_build/hello2/hello2.o

になっていたのだ。
まあ、単なる考慮漏れだ。

 

あれこれ考えたが、このMakefileはオブジェクトファイルを同じディレクトリに放り込むので、$(notdir)でパスを取り除けばよかろう、という結論に至った。
https://github.com/hirokuma/makefile_hello

オブジェクトファイルを同じディレクトリに置くことの弱点は、同じ名前のソースファイルがあるとダメだ、ということだろう。
一人でやっていると起きないけど、複数人でやっているとやらないとも限らない。
関数名はファイル名に関連したプレフィクスを付けるルールにしておけば対応できると思うが、名前が長くなるのが悩みどころだ。

2017/05/15

[ble]BLE NanoでnRF Snifferを動かす

nRF Snifferという、nRF51 DKなどで動かせるスニファがある。
ファームウェアもあるし、COMポート経由でWindowsとアクセスするようだから、別にnRF51 DKじゃなくても動かせそうな気がする。

 

対応しているハードウェアは、こうなっていた。
nRF-Sniffer-UG

• nRF51822 Evaluation Kit (PCA10001) and a mini USB cable
• nRF51422 Evaluation Kit (PCA10003) v3.0.0 or later and a mini USB cable
• nRF51822 Development Kit dongle (PCA10000)
• nRF51-DK (PCA10028) v1.0.0 or later and a micro USB cable
• nRF51 Dongle (PCA10031)

nRF51822とnRF51422が混ざっているが、使うのはBLEだけだからどっちでもよいのだろう。


nRFgo Studioでファームを焼く。
ちゃんと動いているかどうかは、PCA10001かPCA10003ならAdvertisingの検出でLED1がトグルするらしい。

PCA10001の図面を見ると、LED1はP0.19につながっている。
BLE nanoのP0.19もLEDにつながっている。
が、PCA10001はHで点灯、BLE nanoはLで点灯になっている。。。

あ、これは気にしなくていいか。
逆になっているだけだ。
AdvertisingするPeripheralを動かすと・・・点滅した!


次はUARTだ。

nRF51 DKやPCA10001はUSBでPCとつなぐので、ぱっと見てnRF51のどのポートかわからん。。。
nRF51 DKのUsers Guideに「4.2 Virtual COM port」という章があり、以下の表が載っていた。

image2

P0.09がTXD、P0.11がRXD、でよいのか?
それなら、BLE nanoもそうなっている。

あとは、問題になるとすれば通信速度だろうか?
よくわからんので、Snifferに入っていたexeファイルを実行した。
・・・とりあえず、ダメなようだ。

AppDataの下にログが入っているので確認すると、

Cannot configure port, some setting was wrong

などといわれている。
エラーは87番になっていて、検索すると

ERROR_INVALID_PARAMETER
87 (0x57)
The parameter is incorrect.

らしい。
Prolificのではダメなのかも。

何も考えず、BLE nano用のUSB-I/Fに挿してからexeを起動させると動いた。
考えすぎだ。。。


操作できるようなコンソール画面が出てきたものの、Advertisingしている機器の一覧が表示されない。

ログファイルを見てみると、Firmware versionは取得できているが、Invalid packetというエラーがたくさん出ている。
ここまでくると、もうよくわからんな。。。

 

ロジアナでUARTを計測した。
何か送信し続けているようなので、TXDを見てみる。

image3

これは10MHzサンプリングだから、まあ足りてないことはないだろう。
1bitが2.1usくらいだから、1/(2.1*10^-6)=476190.4762。
465kbpsくらいか?
460kbpsでよいかもしれん。

 

うちにあるBLE NanoのUSB I/F(MK20)がその速度に対応できないだけじゃなかろうか。
以前購入した、aitendoのUSB-UART変換モジュールをつなげた。
ああ、動くじゃないか。。。
CTS/RTSがないので、そこはGNDに落とさないといかんようだ。

 

image9

 

Wiresharkも、1.12.13をインストールし、スニファアプリが動いている状態で起動させ、Users Guide PDFのTroubeleshootingを読みながらpipe(\\.\pipe\wireshark_nordic_ble)を設定すれば、アタッチしてBLEパケットを読み取ることができた。
(うちはWireshark2も使いたいのだが、そっちをインストールするとスニファがレジストリを見てしまうせいか、2の方を起動しようとしてしまうのだ。)

あまり深く触っていないが、ここまで動けば他も動くんじゃなかろうか。

 

スニファのHEXファイルも、mbedっぽくD&Dして書込めば済んだような気がする。
USB-I/Fが誤算だったが、今は新しいタイプになっているようなので、もしかしたらそっちだと普通にいけるのかもしれない。

2017/05/14

[win10]MS17-010 の適用

なんだか世間では、ランサムウェアのWannaCryptなるものが流行っているらしい。
あらやだわ、ということで、うちのWindows10(Creators Update後)がちゃんと対策されているかどうか確認したい。

 

ランサムウェア WannaCrypt 攻撃に関するお客様ガイダンス

  • MS17-010をインストール
  • マルウェア対策製品を最新にしておく
  • SMBv1を無効にしておくと、さらに安心かも

 

対策製品を最新にしておくのは、このPCはWindows Defenderしか使っていないので、Windows Updateしておけばよいだろう。

SMBv1はここで無効にできる。

image

が、さて、これを無効にしても大丈夫だったっけ?
Sambaで使われていなければ大丈夫な気がするが、はてさて。

ファイル共有で利用されている SMB のバージョンを確認する方法 | Hebikuzure's Tech Memo
DEPENDENCIESは「MRxSmb20」になっていたから、SMBv2を使っているのか?
でも、このSMB 1.0のサポートにはチェックが入っているのだが。。。

とりあえずチェックを外して、アクセスできなかったら戻そう。
再起動がいるようなので、後で確認する。


そして、対策であるMS17-010だ。

マイクロソフト セキュリティ情報 MS17-010

緊急なのは分かるのだが、Windows10だけでこんだけ書いてあるのだ。

image

どれだよ!
まあ、半分は32bit/64bitの違いなので、3つしかないとはいえ、どれが自分用なのかわからん。

Versionは、Windowsのバージョンだろうとは思うが、今使っているPCはこうなっている。

image

そう、該当するバージョンがないのだ。。。
だから、既に対応されていると考えることもできるし、この記事が2017年3月15日だから、まだこのバージョンは正式になっていなかったと考えることもできてしまう(うちがv.1703にしたのは2017/4/18のようだ)。

とりあえず、一番上のバージョン無しを試してみたが、これはインストールできなかった。
バージョンはこういう関係のようだ。

  • バージョン無し: 2015年7月にリリースされた初期バージョン
  • 1511: 2015年11月
  • 1607: Anniversary Update
  • 1703: Creators Update


PSA: Massive ransomware campaign (WCry) is currently being conducted. SMB v1 (MS17-010) is the primary attack surface. All desktop and server versions of Windows from Vista to 10 are affected. Make sure your machines are patched to avoid infection. : pcma
こちらでは、1703ではKB4016871で対応されている、と書かれている。
うん、そのKBならうちのPCもインストールされている。

 

2017年 5月マイクロソフトセキュリティ更新プログラムに関する注意喚起(JPCERT)
ここで「リモートからの攻撃によって任意のコードが実行される恐れがあります」と書いてあるので、2017年5月のアップデートが入っていれば大丈夫なのかな。

 
大丈夫かどうかって、実際に攻撃を受けるまでわからないから怖いのだな。。。
 

2017/05/13

[ble]BLE NanoとJ-Link LITEをつなぐ

過去の私もやっているが、やはりBLE NanoとJ-Link LITEをつなぎたい。

hiro99ma blog: [ble]BLE nanoを使う

1.27mmのところをどうするかだけが問題なのだが、前回もかなり無理やりつなげている。
そろそろ、何か治具を作った方が良いんじゃなかろうか。

 

1.27mm--2.54mm変換基板が余っているので、ぜいたくに使うことにした。

image

 

内側はこうなっている。
4本が上の方に集まっていてよかった。

image

 

BLE Nanoに挿す方は、前回と同じだ。

image

 

簡素な作りだが、動けばよかろうなのだ。

2017/05/12

[ble]BLE NanoとUSB-IFでKeilにつなぐ

過去の私は、BLE Nano(ノーマル)に、USB-I/FだけでKeilを使ったデバッグができていたらしい。
hiro99ma blog: [ble]BLE nanoを使う

が、疲れていたのか、酒飲みながらだったのか知らないが、どうやってつなげていたのか書いていない。
私のばか。。。


まず、USB-I/FをDAPLINKにしなくてはならないだろう。
これは、上記リンク先だったり、数日前の記事だったり、その辺を読んでUSB-I/Fのファームウェアを書き換えればよいだろう。

 

USB-I/Fをつないでない状態で、nRF5 SDKのKeilプロジェクトサンプルを立ち上げる。
ちょっと古いが、nRF5 SDK v11.0.0を使うことにする。
PCA10028用プロジェクトを開き、デバッグ設定を"CMSIS-DAP"にして見てみる。
   examples\ble_peripheral\ble_app_hrs\pca10028\s130\arm5_no_packs

image

まあ、未接続だからな。
では、つないで、開き直してみよう。

image

あ、見えてる。
では、とKeilツールバーにある「d」っぽいアイコンをクリック。
・・・失敗した。

Build Outputに「No Algorithm found」と出ているので、先ほどのDebug設定の反対側のタブを開いてみた。

image

ああ、ないね。
nRF51xxxがそれっぽいので、Addした。

image

これで「d」をクリックすると、デバッガが起動してmainで止まってくれた。


そういうわけで、前回は特に書くことがなかったので、書かなかっただけと思われる。

[clang]uint64_tのprintf

最近、64bit型を使うことが増えてきた。
その場合は、uint64_tにしている。

デバッグで値を標準出力に出したい場合、printf()を使っている。
そのとき、"%d"なんか使うと、warningが出てしまう。

今使っている環境では、

printf("%llu\n", (unsigned long long)value);

などとしている。

 

これでも困りはしないのだが、キャストが長すぎる。
確か、uintXX_t系の書式が定義されていたはずだ。。。


困ったときは、オライリーのCクイックリファレンスだ。
さすがにここは、古い本には載っていない。

目次で見つけたのは、「第18章 標準ライブラリ関数」のprintfだ。
持っている本では、p.520の表18-9に載っていた。stdint.hで定義されているらしい。
ふむふむ、uint64_tで16進数だったら「PRIx64」でよいようだ。

#include <stdio.h>
#include <stdint.h>


int main(int argc, char *argv[])
{
    uint64_t val = 0x123456789abcdef0ULL;

    printf("val = %" PRIx64 "\n", val);
    return 0;
}

しかし・・・コンパイルエラーが出る。。。

 

なぜだ。。。
他のページを見直すと、「16.3 標準ヘッダの内容」にも同じような内容が書かれていた。
しかし、p.287を見ると「<inttypes.h>」となっている。

#include <stdio.h> #include <inttypes.h> int main(int argc, char *argv[]) { uint64_t val = 0x123456789abcdef0ULL; printf("val = %" PRIx64 "\n", val); return 0; }

コンパイルが通るではないか!

というわけで、p.520の表18-9は、stdint.hにあるのは整数型の型だけで、変換して石マクロはinttypes.hにあるのを覚えておきましょう。


ちなみに、今回使った「PRIx64」がどういうマクロなのか、printf("%s\n", PRIx64)で見てみました。

lx

えー、そうなの。。。

ちなみに、

PRIu64 : "lu"
PRIi64 : "li"

でした(Bash on Windows)。

2017/05/08

BLE-Nano+USBでHEXファイルが焼けない (2)

昨日の続きだ。
久しぶりにBLE-Nanoを出してみたが、HEXファイルがうまく焼けなかったので、なんとかしたい。

 

まず、MK20の方から。
うちにあるのは、こちら。

image

こちらの写真と見比べると、MK20 USB V1.0だということがわかる。
そのファームウェアは、こちら。
BLENano/USB-IF/MK20-USB/board_v1.0 at master · RedBearLab/BLENano

これをダウンロードして、MK20はRSTボタンを押したままUSBポートに挿し、Windowsが認識するのを待つ。
そうすると「BOOTLOADER」というラベル名のドライブとして見えるので、ダウンロードしたファイルをD&Dで書込む。
LEDが高速点滅したら終わりらしいので、USBポートから外す。

 

もう一度USBポートに挿すと、「DAPLINK」というラベル名のドライブとして見えた。
では、何か焼いてみよう。

RedBearLab BLE Nano | mbed
ここに、LED点滅のHEXがあるから、それをドライブにD&Dしてみる。。。

image

あれ、点滅しない??
何か間違っているのか・・・。

あ、LEDはこっちじゃなくて、BLE-Nanoにも載ってるんだ。

image

こちらは無事に点滅していた。

 

・・・もしかしたら、昨日焼けないと思っていたのは、単に見ているLEDが違っていただけかも、と思ったが、いやいや、HEXファイルをドライブにD&DしたらUSBから取り外された動作をしていたので、それ以前の問題だったのだ。

 

そんなわけで、Windows10でうまくいかなかった人は、firmwareを書き換えてみるとよいかもしれん。

BLE-Nano+USBでHEXファイルが焼けない (1)

机の片付けをしていると、TIのBLEドングルが見つかった。
懐かしいのでノートPC(Windows10)に挿してみたところ、ドライバが認識されなかった。。。
デスクトップPCのWindows10は認識した。

ノートPCは何も設定していなかったので、おそらく今回が初回の接続だったはずで、Creators Update。
デスクトップPCは以前から使用できていて、Anniversary Updateだ。

どの違いが影響しているか分からないので、これはデスクトップPCにCreators Updateがインストールされたときに確認しよう。


ついでに、近くにあったBLE-Nanoも使ってみることにした。
mbedにできるMK20-USBもあるので、挿してHEXファイルをドライブに置いてみた。

しかし・・・焼けない。
途中でUSBを抜いたような音がして、また接続される。
これは、デスクトップPCもノートPCも同じ動作だった。
少なくとも、以前はデスクトップPCでは使えていた形跡があるのだが。。。

DAPLink firmwareなら'DAPLink'、CMSIS-DAP firmwareなら'MBED'というラベル名になるらしい。
そして、うちではMBEDという名前だったから、CMSIS-DAP firmwareが焼かれていたのだろう。

 

RedBearLab BLE Nano | mbed
こっちでは、firmwareとして20140912という日付だから、githubにある方が新しいな。

実は、なんとなくMK20のボタンを押したままUSBに挿してしまい、何か焼くモードになったので、mbedのサイトにある方を焼いてしまったのだ。

 

次回は、githubにある方を焼いてから試すとしよう。
今日やってしまえばよいのだが、もう眠たいのだ。。。

2017/05/07

[bc]segwitのTXID

連休にもかかわらず、書けるような記事が何もない。。。
これではまずいので、困ったときのBitcoinネタを出そう。

 

ビットコイン分裂騒動は「レイヤー2」への反動か | TechCrunch Japan

SegWitを前提としないLightning Network実装は理論的には可能だが、開発者にとって「やりたくない仕事」なのだそうだ

あははは、うまい表現だ。
最初に「segwitなしでLN(LightNing)」という話を聞いたときは、おお!そんなことが!、と思ったけど、どうやって実現するのかを読んでいく途中で「あー、私にはむりー」となってしまった。
(2017/05/10:Lightning Network、の方がふさわしいな。)

 

基本的に、Bitcoinのやりとりは、誰も信用しない、というところを重視していると思っている。
trustless、というやつだ。
現金をBitcoinに替えたりする場合は知らんが、Bitcoinの中だけでもそうなるように苦慮している。
ときどき「そこまでするの??」というような内容もあるのだけど、理論的にツッコミできないので、そういうものかとあきらめている。

雰囲気としては、Bitcoinは秘密鍵とデジタル署名で成り立っている。
もちろん、ブロックチェーンというだけに、ブロックのもつ役割は大きいのだけど、ブロックは何からできているかというとBitcoinの価値を移動させるトランザクションで、トランザクションは秘密鍵でデジタル署名することになっているのだ。

 

トランザクションは、それぞれを識別するIDが付いている。
これが「トランザクションID」(TXID)というやつだ。
どこか中央のサーバがあれば、そこが一意になる値を付ければよいのだが、Bitcoinでは中央がいないので、一意になるような値をがんばって付けなくてはならない。
連番にしてしまうと、ネットワークの転送時間などもあって、同時に同じ番号を付けられてしまうこともあるだろう。
だからだと思うが、トランザクションIDはトランザクションの中身を使って算出するようになっている。
ハッシュ値、というやつですな。

 

そのトランザクションIDの計算をする方法が、非segwitとsegwitで異なる。
非segwitの場合は、トランザクションの中身だけで計算できた・・・と思う。
しかしsegwitの場合、従来の計算方法を使ったIDの算出方法と、新しい計算でのID算出方法がある。
そして、非segwitのトランザクションIDと同じ位置にいるのは、新しい計算でのIDの方である。

 

新しい計算方法の特徴は、

  • そのトランザクションのINPUTがいくらのBitcoin量(amount)だったかを計算に含める
  • そのトランザクションのデジタル署名は計算に含めない

だと思う。
前者は、確かトランザクション展性という脆弱性に対応するため(だったと思う)。
最初の記事に出てくる「レイヤー2」にとっては、後者の方が欲しい。

2017/05/10追記
この計算方法は、署名についてだった。。。
TXIDについてはトランザクションの中身だけで計算できるが、計算に含める部位と演算方法が違う。
その部位に署名(witness)が入らないため、TXIDは署名をする前に計算できる。

なお、WTXIDというものもあり、これは従来と同じ計算方法のため、署名もひっくるめてハッシュ計算している。

記事を読んでいると「チャネル」という言葉がしばしば出てくると思う。
これは「私とあなただけがやりとりする口座」みたいな意味だ。
テレビやラジオのチャンネルよりも、Amazonなどのログインアカウントみたいな意味合いの方が強いかな。

Bitcoinで口座に相当するものといえばBitcoinアドレスになるが、ここは「私とあなた」なので、2-of-2のmultisigアカウントを作ることになる。
Bitcoinのアカウントを作るだけなら何とでもできるが、それをBlockchain上に見えるようにするには、既にあるトランザクションからそのアカウントに送金してもらうことになる。
だから、レイヤー2のアカウントを作る=そこに入金する、ということになる。

が、2-of-2のmultisigに入金するということは、2人ともデジタル署名をしないとお金を取り出せないということでもある。
もし相手が偽物だったり、入金した後に逃げられて取り戻せなくなったりするのでは・・・・という心配が残る。
これが、「trustless」が重視される理由だ。
相手が悪いことをしても、少なくとも自分は損をしない、下手をしたら悪いことをした人が損をする、というくらいのことを、計算上で実現させるようにしている。
計算上というか、Bitcoinの支払いスクリプトで、そうなるようにがんばっているのだ。

相手から署名してもらわなくてもTXIDが計算できるということは、multisigへ入金したとして、そこから自分に取り戻すトランザクションを署名無しで作ることができるという意味でもある。
そこまで保険を掛けておけば、取り戻すトランザクションが手元にあるので、相手が逃げるかどうかはわからないけどチャネルを開いても少なくとも損はしない、という安心感が得られる。

 

こういう、異常系というか純正常系というか、そういう部分がレイヤー2の大半を占めるので、けっこう大変なのだよ。。。

2017/05/02

[golang]値を複数返す関数があるが、片方しかいらない

久々にgoで書かれたソースを見ている。
相変わらずわからんが、動かすことはできるので、fmt.Printf()を埋め込んで動きを見ている。

 

A1という関数を使っている箇所があり、それと似たA2という関数を使った場合の違いを見ようとした。
そのA2という関数は、値を2つ返すようになっているのだが、私は1つしか使わない。
まあよかろう、と適当な変数に代入させたのだが、エラーになってしまった。
どうも、未使用の変数があるとエラー扱いになるようなのだ。

じゃあもう片方も無理やり使ってやればよいのだろうが、使い道が思いつかない。。。
試しに、いる戻り値しか取得しないようにしたがエラーになるし、コンマだけで数をごまかそうとしてもエラーになった。
うーん。。。

 

未使用の変数/インポートに対するエラーを抑止できますか?
変数として「_」を使えばよいということか?
試しにやってみると、エラーが消えた。
Pythonもそういえば、「_」を使って回避できたような気がする(deleteで消した方がよいかもしれんが)。

2017/05/01

「ChaCha20 and Poly1305」は「ChaCha20-Poly1305」でよい気がしてきた

数学が専門ではないと逃げようとしたが、理論的な導出はわからないだろうし、導かれた結果が正しいかどうかは分からないかもしれないが、結果を利用するのは常套手段でなくてはならない。

前回、ChaCah20が出てくるRFCで、私が知りたかったのは「RFC-7539」、TLS/SSLに出てくるRFCは「RFC-7905」で、数字が違うのだから、きっと中身も違うはずだ、と何も考えずに結論してしまった。

 

しかし、そうなのだろうか?
RFCの番号が違うとか、RFC-7539の中に「7905」という数字が出てこないとか、そんな見た目だけのことで思考を止めてはいけないのではなかろうか、と考え始めた。

内容は分からないにしても、思考停止するのはよくないだろう。
せめて、自分なりに調べてみて、わからなければあきらめる、くらいのことをしてもよいはずだ。


RFC 7905 - ChaCha20-Poly1305 Cipher Suites for Transport Layer Security (TLS)

一番簡単なところから始める。
さっきは、RFC-7539の中に「7905がない」というだけで済ませてしまったが、その逆を考えてなかったのだ。

果たして、RFC-7905の中には、RFC-7539への参照が書かれていた。
無関係ではないのだ。
しかも、文中で4回も参照されている。

RFC-7905を眺めたが、ここにはアルゴリズムのことは書かれておらず、TLSの暗号suiteとしてのChaCha20 and Poly1305のことが書かれているだけのようだ。
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256など、どの組み合わせを使うかということだけが書かれているのか。

では、方向性は間違ってなかったのかも。


AEAD_CHACHA20_POLY1305の要求がどうのこうの書かれているが、そういうのはここを読んでいくのがよさそうだ。

新しいTLSの暗号方式ChaCha20-Poly1305 - ぼちぼち日記

上の方しか読んでなかったけど、ちゃんとChaCha20の説明とPoly1305の説明が出ているじゃないか。。。

ChaCha20-Poly1305は「認証付き暗号」という種類で、認証付き暗号はAEADという略称らしい。
Poly1305は16byteのMAC値を生成するようで、計算したときも16byte増えていたから、暗号化した結果にMACを付けることを認証付き暗号と呼ぶのだろうか。

 

アルゴリズムは分かっていないが、なんとなく雰囲気は分かった気がするので、ChaCha20関連はこれで終わりにしよう。

2017/04/30

「ChaCha20 and Poly1305」は「ChaCha20-Poly1305」ではないだろう

ChaCha20を調べ始めたとき、私はリンク先を載せていた。
それは、RFC-7539だ。

こちらを読んでいたのだが、出てきたのはRFC-7905だった。
新しいTLSの暗号方式ChaCha20-Poly1305 - ぼちぼち日記

RFC-7539 : ChaCha20 and Poly1305 for IETF Protocols
RFC-7905 : ChaCha20-Poly1305 Cipher Suites for Transport Layer Security (TLS)

えっ、別物???
私が調べないといけなかったのは「ChaCha20 and Poly1305」で、「ChaCh20-Poly1305」ではなかったということか。
最初に正しいリンク先を示しておきながら、どんどん違った方向にミスリードさせていくとは、なんたるトリックよ。。。

もちろん、ブログに書いているのは氷山の一角で、あれこれ調べたり悩んだりし続けていたのでした。


あまりにガックリしたので、今回はこれまで。

[clang]よくわからずchacha20する

「よくわからず」は、まだ甘い表現だ。
「まったくわからず」と言った方がよいのだが、取りあえずchacha20で何かしてみよう。

今回は、libsodumを使う。


[gist]libsodium1

よくわからないまま、chacha20という名前が入っていたAPIを使う。
。。。使おうとしたが、xchachaやchacha_ieftなどの種類があった。
結果も異なる。。。

ChaCha20-Poly1305のサンプルがあったので、少しだけ変更した。
MESSAGEに入れたデータは、encryptしてdecryptするとちゃんと復元される。

enc= 8eb13143515e31c709aabdb474a9f910a929b6389c4abaac90c62e5511bdb0ab1186

dec= 64(d) 69(i) 67(g) 69(i) 74(t) 61(a) 6c(l) 20( ) 74(t) 65(e) 6c(l) 65(e) 76(v) 69(i) 73(s) 69(i) 6f(o) 6e(n)

"digital television"が18文字で、encryptすると34byteだから、+16byte。
"test"は4文字で、encryptすると20byteなので、+16byte。
crypto_aead_chacha20poly1305_ABYTESが16byteだった。

 

いやあ、さっぱりわからんね。。。
ストリーム暗号だから、暗号にする単位ごとに16byteあればよいということだろうか。

2017/04/29

Poly1305

前回、Chacha20が使えるライブラリを調べた。
しかし、何か忘れている気がする・・・と思ったら、RFCではChacha20-Poly1305となっている。

Poly1305とはなんだろうか?


メッセージ認証符号とのこと。
Poly1305 - Wikipedia

メッセージ認証符号ってなんだ?と調べると、「メッセージを認証するための短い情報」ということだ。
メッセージ認証符号 - Wikipedia

MACは、FeliCaでも出てきたな。

INPUT1: 共通鍵
INPUT2: メッセージ
OUTPUT: MAC値

メッセージが変わると、MAC値も変わるので、書き換わってないことが確認できるということらしい。
デジタル署名と似たような感じがするが、あっちは秘密鍵で符号化して公開鍵で復号するタイプだった。
そして、秘密鍵で署名する場合は「秘密鍵を知っている=持ち主」という図式になっているので、署名を作った人はメッセージを符号化した人と同じと見なせるが、MACは共通鍵なのでそれができない(というのが、否認不可性をもたない、ということだろう)。

じゃあ、デジタル署名の方が優れているじゃないか、ということになってしまうが、MACの方が処理が軽いのかな?
デジタル署名ほどの機能は求めていないシーンもあるだろうから、そういう場合によいのかも。
この辺は、とても疎いので逃げておこう。。。

 

Poly1305の「1305」は、2130-5が素数だからら・・・って、いきなり素数のこと出てきてもわからん。

poly1305.dvi - poly1305-20050329.pdf

The Poly1305-AES formula is a straightforward polynomial evaluation modulo 2130-5;

うーん、moduloに関係していることは分かるのだが、まあ専門家じゃないので、ここも見なかったことにしておこう。

 

WikipediaのPoly1305には、オリジナルは「Poly1305-AES」と書かれている。
TLSでは、AESではなくChaCha20を使うと書かれているが、こっちは「ChaCha20-Poly1305」と順番が逆だ。
AESはブロック暗号で、ChaCha20はストリーム暗号だから、それを取り替えただけだろうと思うのだが、計算順序が違ったりするのだろうか?

 

まあいい。
既に自分で実装する気がないので、ライブラリさえあればよいのだ。
ともかく、ChaCha20だけではダメで、Poly1305も一緒にやらないとダメということはわかった。

前回調べた、ライブラリになっていないソースは、ChaCha20だけだ。。。というか、この人、ChaCha20自体の考案者やん!
Salsa20ときて、ChaCha20ときているから、ダンスの名称(だっけ)からとった名前のようだ。
そのうち、ジルバなんかも出てくるのだろうか。

ごにょごにょ調べていたが、ここを読んだ方がわかりやすいと思う。
新しいTLSの暗号方式ChaCha20-Poly1305 - ぼちぼち日記


libsodiumやwolfSSLはChaCha20-Poly1305と書いてあるから大丈夫だろう。
mbedTLSが対応するまで、それでしのぐしかないが、configureで移植できない環境に持っていくのは大変そうだ。

2017/04/28

ChaCha20が入っているライブラリ

お仕事で、ChaCha20というものが出てきた。
茶々?

リンクはここになっていた。
RFC 7539 - ChaCha20 and Poly1305 for IETF Protocols

stream cipherと書いてあるので、連続するデータをどんどん暗号化できるというものなのだろうか?

ストリーム暗号 - Wikipedia

ああ、AESなどはデータの塊を暗号化するからブロック暗号で、そういう制限がないのがストリーム暗号なのか。

 

残念ながら私は専門家じゃないので、難しいことは分からない。
知りたいのは、自分で実装できるようなものなのか、ライブラリを使った方がよさそうかということなのだが、こういう暗号関係は自分で実装しない方がよいだろう。
間違うと、ひどい目にあうし。

というわけで、ライブラリを探したい。


まず出てきたのが、libsodium。
ChaCha20-Poly1305 · libsodium

wolfSSLにもあった。
wolfSSL - Docs | wolfCrypt Manual - Chapter 18.7 (ChaCha20-Poly1305)

 

では、私がよく使っているmbedTLSにも・・・無かった。。。
Will ChaCha20 and Poly1305 be supported in mbedtls? · Issue #346 · ARMmbed/mbedtls

実装が進んでいる気配はあるが、もう1年前か。
Implement Chacha20 and Poly1305 by damaki · Pull Request #485 · ARMmbed/mbedtls

 

Cortex-Mくらいしか使わないから、小さいのがいいんだけどなぁ、と思ったら、こういうのがあった。
joostrijneveld/chacha-arm-cortex-m: Optimized assembly implementation of ChaCha8/12/20 permutation for ARM Cortex-M3 and Cortex-M4

Cortex-M3とかM4に最適化してあるらしい。
ほうほう、と中身を探したが、chacha20.hはあるが、本体がなさそうだ。
chacha20_perm_asm()をexternしているので、これが本体なのだとは思うが、Googleで検索しても出てこん。
本体は、libopencm3というARM cortex-M用のオープンソースライブラリなのかと思ったけど、うまく探せない。。。

 

ライブラリになっていると、各プラットフォームに移植するときに面倒だったりするから、数ファイルだけでできていて組み込めるのがよいのだけどなぁ。
Chachaだけだったらここにリファレンス実装があった。
The ChaCha family of stream ciphers

ref, regs, mergedって、なんの違いなんだ。。。
使い方がわからんので、同じソースを使っているこちらを読んでみるか。
circulosmeos/triops: triops: a multiplatform command-line encryption tool using CHACHA + KECCAK

2017/04/25

[et]EthereumはJavaScriptがわからないとつらかった

仕事ではほとんどBitcoinしか見ていないのだが、それじゃあんまりだということでEthereumも少し見てみることになった。

環境の作り方はいくつかあると思うが、私がやったのは、

という組み合わせだった。
これも自分で作ったわけではなく、作ってもらったのを使っただけだ。

geth(たぶん、go言語で書かれたethereumエンジンという意味だろう)を動かし、それにJavaScriptのAPIでアクセスするというやり方だ。

 

ethereumは、私から見ると、JavaScriptっぽい言語で動く仮想マシンだ。
EVM、EVMとよく出てくるけど、仮想マシンがEVMね。
JavaScriptのAPIでアクセスするから「JavaScriptっぽい言語」というわけではない。
Solidityという言語でプログラムを書いて、それをブロックチェーンに載せると、燃料(gas)を与えればプログラムが動く、というイメージだ。

JavaScriptからはAPIを経由してSolidityで書いた関数を呼び出す。
関数ではブロックチェーンに書込んだり読込んだりができる。
なんとなく、DBアクセスしている気分だ。

ただ、DBじゃないので、書込んだ値は「自分のノードでそう思っている」というだけで、マイニングされてブロックに組み込まれないと値が確定しない(のだと思う)。
この辺りは、しくみがよくわからんかった。
ライトキャッシュみたいに、自分が書込んだ値を読込めば本体にアクセスせずに読み込めるけど、書込んでない人は本体を読みに行くので、キャッシュが吐き出されるまでは値が変わらない、みたいなことじゃないかなぁ。

 

ドキュメントの更新はそんなに頻繁ではないようで、APIを使ってみたらもう搭載されていなかった、ということがときどきあった。

私が触っていた頃は、ちょうどtestenetのRopstenが攻撃を受けたところで、Parityという別実装のエンジンだと対処法があったのだけど、Gethではどうしようもなさそうだったので、プライベートチェーンを作って試して終わった。


とにかくつらかったのが、Solidityとかじゃなくて、JavaScriptそのもの。
使い慣れていない上に、スクリプト言語自体に不慣れなので、毎日荒れていた(私が)。

また、便利なはずのmeteorも、私にとっては「JavaScriptがよくわからないのに、さらによくわからないものが載っている」ということになり、いろいろつらかった。

つまり、そういう言語に使い慣れている人であれば、敷居はそんなに高くないのかもしれない。
JavaScriptが書ける人であれば、ブロックチェーンのところはSolidityを使える少数の人にやってもらって、周りのアクセスするところは普通のJavaScriptが書ける人で対応できる。

ネットニュースでブロックチェーンを使った実験とかあるけど、多少複雑なことをブロックチェーンだけで完結させたいと思ったら、何かしらブロックチェーンでプログラムが動いてくれる方が便利で、そうなるとEthereumか、という選択になるのだろう。
技術者を集めやすいし、JavaScriptで書ける人はブラウザを使ったサービスなんかをよく作りそうな気がするので、画面の見栄えもよさそうだ。

 

Ethereumはホワイトペーパーとイエローペーパーというものがある。
ホワイトペーパーは日本語訳もあるので、ちょっと読みづらいけど中身としては興味深かった。
Bitcoinを分析しているところなんかも面白い。
[Japanese] White Paper · ethereum/wiki Wiki

イエローペーパーは、いやあ、さっぱりわからなかった。。
http://yellowpaper.io/

このくらいできないと、ブロックチェーン技術者になれないのだろうか・・・。