ssssをgolangに移植してみた

この記事は、Go2 Advent Calendar 2018の9日目の記事です。

qiita.com

以前、ssssを使った秘密分散について書きました。丁度1年ぐらい前ですね。

ohac.hatenablog.com

ssssというのはSSSS.GRIDMANとは全く関係なくて、Shamir's Secret Sharing Schemeのことです。 Shamirというのは人の名前で、RSA暗号のSの人ですね。

で、これを今回Go言語に移植してみました。 というのもこのssssはC言語でコーディングされており、今時の高級言語には移植されていなかったためです。

Go言語ならWindowsやARM用のバイナリを作るのは簡単ですし、最近ではwasmにも変換できるため、 ブラウザ上で動作させるように改造することも容易になります。

ソースコードgithubに置きました。

github.com

とりあえず移植したレベルですので、ライブラリ化やコマンドラインアプリ部分との分離とかはまだやっていません。 git cloneして、go buildすればssssgoというバイナリができますので、以下のような感じで動作させることができます。

ssssgo$ go build

ssssgo$ ./ssssgo -t 3 -n 6 split
Generating shares using a (3,6) scheme with dynamic security level.
Enter the secret, at most 128 ASCII characters: foo bar baz
Using a 88 bit security level.
1-d9bd5efeb34972b41dcb98
2-25c1440f501ee5a1723d81
3-2e14fbbc265d4f36d2ca65
4-bd30c359096f0190188682
5-b6e57cea7f2cab07b87174
6-4a99661b9c7b3c12d78749

ssssgo$ ./ssssgo -t 3 combine
Enter 3 shares separated by newlines:
Share [1/3]: 6-4a99661b9c7b3c12d78749
Share [2/3]: 3-2e14fbbc265d4f36d2ca65
Share [3/3]: 2-25c1440f501ee5a1723d81
Resulting secret: foo bar baz

コマンドライン書き方がちょっとオリジナルとは違うのと、入力文字列が隠れない点が移植しきれていませんが、ちゃんと動いていることが分かります。

今回はAdvent Calenderの記事でもありますので、git log -pを見ながら移植についての感想みたいなものを書こうかと思います。

最初はやはり勢いが大事です。まずは拡張子.cを.goに書き換えて、go fmtが動くところまで持ってきました。 ただし、ややこしそうなところや、最初の目標と考えていたsplit部分以外はひとまずコメントアウトしました。

で、一番の不安要素としてはgmpの部分をどうやって移植すればよいかと考えていました。 mini-gmpを移植しないといけないのかと。

1つ見つけたのは github.com/ncw/gmp というパッケージで、これはlibgmpをgolangから呼べるようにするもののようでした。

github.com

gmpというのは何なのかを調べたところ、大きい整数を扱うための高速なライブラリのようでした。 gmpGNU Multi-Precision Libraryの略だそうです。

GNU Multi-Precision Library - Wikipedia

今回は高速動作は重要ではないですし、整数のライブラリなら他にもあるだろうと調べたところ、普通に標準ライブラリにありました。math/bigというやつで、この中のInt部分です。

big - The Go Programming Language

この時点での移植プランとしては、とりあえずncw/gmpを使って動作するところまで持っていき、その後でmath/bigへ移植しようと考えました。 ncw/gmpはmath/bigと同じようなインターフェイスを持っているため、ncw/gmpで動けば、ほぼそのままmath/bigでも動くだろうし、libgmpの関数とmath/bigでの呼び方の対応を見るにはncw/gmpソースコードを見れば分かりそうだったので、非常にありがたかったです。math/bigへの移行はgmp.Intをbig.Intに書き換えるだけです。

オリジナルの乱数は乱数プールから値を読むような処理がありました。これは最初はmath/randのUint32()を使っていましたが、セキュアでないため後でcrypto/randに置き換えました。(wasm化する場合はこれはJavaScriptのSecureRandomあたりにバインディングされるのではないかと思いますが、調べていません。SecureRandomは古い実装だとMath.randomにfallbackする問題があるらしいですが、wasmが動くような最近のブラウザはたぶん大丈夫なのかもしれません。すんません調べていません。)

ということで、できていないところとしてはメモリのロック処理(mlockall)、uidの処理(seteuid)、secret入力時のecho offがありますが、本質的な部分ではないので今はあまり移植するモチベーションがありません。

まとめ

C言語で書かれているコードをWindowsやRasPiやブラウザで動かしたければまずは拡張子を.goに書き換えることからスタートしてみてはいかがでしょうか。