Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

BLS署名の実装とその応用

421 views

Published on

CSS2020 3D2-1の発表資料

Published in: Technology
  • Be the first to comment

  • Be the first to like this

BLS署名の実装とその応用

  1. 1. BLS署名の実装とその応用 2020/10/28 CSS2020 3D2-1 サイボウズ・ラボ 光成滋生
  2. 2. • BLS署名の定義 • 集約署名 • 閾値署名 • multiVerify • 実装詳細 • GMP • LLVMのDSL • Xbyak • ベンチマーク 概要 2 / 19
  3. 3. • ペアリングベースの短い署名 • Boneh, Lynn, Shacham(2001) • 実装では高速性のため(非対称)type-3ペアリングを利用 • ペアリング • 𝑒: 𝐺1 × 𝐺2 → 𝐺 𝑇 ; 𝐺𝑖は位数𝑟の巡回群 • 𝐺𝑖 = ⟨𝑃𝑖⟩, 𝑔 ≔ 𝑒(𝑃1, 𝑃2) ; 𝐺 𝑇の生成元 • 𝑒 𝑎𝑃1, 𝑏𝑃2 = 𝑔 𝑎𝑏 for 𝑎, 𝑏 ∈ 𝔽 𝑟 • type-3; 𝐺𝑖から𝐺3−𝑖(𝑖 = 1,2)への効率的に求まる同型写像がない • 128ビットセキュリティの曲線 • BN254は100~110ビットセキュリティ(by Menezesら) • BLS12-381がよく利用されている(2017 by S. Boweら) • BLS=Barreto, Lynn, Scott BLS署名 3 / 19
  4. 4. • 記号 • 𝐻𝑖: 0,1 ∗ → 𝐺𝑖 ; ハッシュ関数 • 添え字 𝐼, 𝐼′ = (1,2) or (2,1) ; 非対称なので2種類ある • ൗ𝐺𝑖 𝔽 𝑝 𝑖なので𝐺2の元の𝐺1の2倍 • 鍵生成 • 𝑠 ՚ 𝑅 𝔽 𝑟(一様ランダム); 署名鍵, 𝑄 ≔ 𝑠𝑃𝐼′ ; 検証鍵 • メッセージ𝑚 ∈ 0,1 ∗ に対する署名 • 𝜎 ≔ 𝑠𝐻𝐼 𝑚 ∈ 𝐺𝐼 • 署名𝜎, 検証鍵𝑄, メッセージ𝑚に対する検証 • 𝐼, 𝐼′ = (1,2)なら𝑒 𝜎, 𝑃2 = 𝑒 𝐻1 𝑚 , 𝑄 ; 署名-小/検証鍵-大 • 𝐼, 𝐼′ = (2,1)なら𝑒 𝑃1, 𝜎 = 𝑒(𝑄, 𝐻2 𝑚 ) ; 署名-大/検証鍵-小 BLS署名のアルゴリズム 4 / 19
  5. 5. • 検証鍵と署名が「スカラー×群要素」の形 • 𝑄 ≔ 𝑠𝑃𝐼′, 𝜎 ≔ 𝑠𝐻𝐼 𝑚 • 集約署名 • ℎ: 0,1 ∗ → 𝔽 𝑟 ; ハッシュ関数 • 𝑛個の署名を集約して検証コストを減らす仕組み • 𝑠𝑖 ; 秘密鍵, 𝑆𝑖 ≔ 𝑠𝑖 𝑃𝐼′, 𝑄𝑖 ≔ ℎ 𝑆𝑖 𝑆𝑖 ; 公開鍵 • 𝑚に対する署名𝜎𝑖 ≔ ℎ 𝑆𝑖 𝑠𝑖 𝐻𝐼(𝑚) • 集約 • 署名の集約𝜎 ≔ σ𝑖 𝜎𝑖 = σ𝑖 ℎ 𝑆𝑖 𝑠𝑖 𝐻𝐼 𝑚 • 公開鍵の集約𝑄 ≔ σ𝑖 𝑄𝑖 = σ𝑖 ℎ 𝑆𝑖 𝑆𝑖 = σ𝑖 ℎ 𝑆𝑖 𝑠𝑖 𝑃𝐼′ • 検証 • {𝜎, 𝑄, 𝑚}に対する通常のBLS署名の検証と同じ BLS署名の特長 5 / 19
  6. 6. • 𝑛個の署名のうち任意の𝑡個の署名を集めるとマスター 検証鍵で復号可能な署名を作成できる • 鍵配付 : ディーラーが𝑡 − 1次𝔽 𝑟係数多項式𝑓(𝑥)を選ぶ • 𝑠 ≔ 𝑓(0)がマスター署名鍵, 𝑄 ≔ 𝑠𝑃𝐼′がマスター検証鍵 • 各メンバー𝑖に鍵シェア𝑠𝑖 = 𝑓(𝑖)を配付(𝑖 = 1, … , 𝑛) • 𝑠𝑖が署名鍵, 𝑄𝑖 ≔ 𝑠𝑖 𝑃𝐼′が検証鍵 • {𝑠𝑖}は𝑠に対するShamirの秘密分散 • 署名 : 𝑚に対する通常のBLS署名𝜎𝑖 ≔ 𝑠𝑖 𝐻𝐼(𝑚) • 復元 : メンバーのうち任意の𝑡人の集合𝑆 • {𝜎𝑖: 𝑖 ∈ 𝑆}から𝑓 0 𝐻𝐼 𝑚 = 𝑠𝐻𝐼(𝑚)を復元できる • ここから𝑠は求められない • この署名の正しさはマスター検証鍵で検証可能 • ブロックチェーン上での多数決に利用可能 𝑡-of-𝑛閾値署名 6 / 19
  7. 7. • 複数のBLS署名をまとめて検証する • Ethereumでは400個程度の署名{𝜎𝑖}を検証 • 素朴な実装 • 一つ一つ検証を行う • 一つの検証の改良 • ペアリングの性質による式変形 • 𝑒 𝑃, 𝑄 = 𝐹𝐸 𝑀𝐿 𝑃, 𝑄 • ML ; Miller Loop, 𝐹𝐸 𝑥 = 𝑥 𝑟0, 𝑟0 ; constant factor • 処理コスト ML : FE = 2 : 3 • verification : 𝑒 𝑃1, 𝜎 = 𝑒(𝑄, 𝐻2 𝑚 ) --- (*) ; 2ML + 2FE • (*)⇔ 𝑒 𝑄, 𝐻2 𝑚 𝑒 −𝑃1, 𝜎 = 1 ⇔ 𝐹𝐸 𝑀𝐿 𝑄, 𝐻2 𝑚 𝑀𝐿 −𝑃1, 𝜎 = 1 ; 2ML + 1FE multiVerify 7 / 19
  8. 8. • 検証式を統合 • 𝑒 𝑃1, 𝜎𝑖 = 𝑒(𝑄𝑖, 𝐻 𝑚𝑖 ) for 𝑖 = 1, … , 𝑛 • ランダムな𝑟𝑖に対してς𝑖 𝑒 𝑃1, 𝜎𝑖 𝑟 𝑖 = ς𝑖 𝑒(𝑄𝑖, 𝐻(𝑚𝑖)) 𝑟 𝑖 -- (*) が成立→無視出来る確率(~1/|𝑟𝑖|)を除いて全ての等式が成立 • (*)⇔ 𝐹𝐸 ς𝑖 𝑀𝐿 𝑄𝑖, 𝐻2 𝑚𝑖 𝑟 𝑖 𝑀𝐿 −𝑃1, 𝜎𝑖 𝑟 𝑖 = 1 ⇔ 𝐹𝐸 ෑ 𝑖 𝑀𝐿 𝑟𝑖 𝑄𝑖, 𝐻 𝑚𝑖 𝑀𝐿 −𝑃1, ෍ 𝑖 𝑟𝑖 𝜎𝑖 = 1 • 𝑛(2ML+1FE) → 𝑛 + 1 ML + 1FE • σ𝑖 𝑟𝑖 𝜎𝑖 ; multi scalar演算, ς𝑖 𝑀𝐿 ; multi Miller Loop • この変形によりシングルスレッドで約2倍の高速化 • ς𝑖 𝑀𝐿をマルチコアで実行 • 4コアで5.7倍、12コアで12.8倍 multiVerify 8 / 19
  9. 9. • OSS(オープンソースソフトウェア) • mcl ; ペアリングライブラリ https://github.com/herumi/mcl • bls ; mclを用いたBLS署名ライブラリ • 特長 • Windows, Linux, macOS, Android, iPhone, Node.js対応 • x64, aarch64, WebAssembly, ARM, MIPS対応 • Go, Rust, C#, JavaScriptなどの言語バインディング対応 • 階層構造 実装 BLS署名bls ペアリングmcl 楕円・有限体 固定長整数演算 Xbyak LLVM GMP pure C++ 9 / 19
  10. 10. • C++03(古いC++) • たまに古い環境で動かしたいという要望 • clangでもWebAssembly版で新しいC++が動かないことがある • 例外機構を使わない • 動的メモリ確保をしない • 組み込み環境で扱いやすい • GC(ガベージコレクション : 不要なメモリを自動解放)の ある言語で扱いやすい 実装方針 10 / 19
  11. 11. • pure C++版 • 移植性優先 • GMP • さまざまなアーキテクチャ向けに最適化された 多倍長演算ライブラリ • mpn_*という低レイヤの高速な関数を呼び出す形で利用 • 動的メモリ確保は行わない • GPLのため利用したくないケースがある 固定多倍長演算の実装 11 / 19
  12. 12. • LLVM • さまざまな言語を開発するための開発基盤 • 独自の仮想機械(VM)上の実行環境で動作するコンパイラ • VM用コードから実際のアーキテクチャ用コードへの変換機構 • aarch64, MIPS, WebAssemblyなど対応 • 高度な最適化機構 • 任意ビットサイズの整数演算レジスタ LLVMを利用した固定多倍長演算の実装 12 / 19
  13. 13. • LLVMビットコードによる加算の例 • 型情報の表現が冗長 • 静的単一代入系SSAのため複雑なコードは変数が増大 • 手書きが大変 LLVMビットコードの例 define void @add(i192* %pz,i192* %px,i192* %py) { %x = load i192, i192* %px %y = load i192, i192* %py %z = add i192 %x, %y store i192 %z, i192* %pz ret void } 13 / 19
  14. 14. • DSL(ドメイン特化言語) • C++で書きやすいDSLを開発 • DSLを用いて有限体の演算やMontgomery乗算などを実装 • LLVMのツールにより各CPU向けのアセンブリ言語を出力 LLVMのための簡易DSL codeGen LLVMビットコード code written by DSL for LLVM x64 asm aarch64 asm wasm ...LLVM opt+llc 14 / 19
  15. 15. • 有限体𝔽 𝑟上の引き算 • 擬似コード sub(x, y)={ t := x - y; if (t < 0) t += r; return t; } DSL for LLVMの例 N ; ビット長(bit) / word長 Operand x = loadN(px, N); // アドレスpxから読みxに代入 Operand y = loadN(py, N); // アドレスpyから読みyに代入 Operand v = sub(x, y); // v = x - y Operand c; c = trunc(lshr(v, bit - 1), 1); // c = (v>>(bit-1)) & 1 Operand p = loadN(pp, N); // アドレスppから位数pを読む c = select(c, p, makeImm(bit, 0)); // c = c ? p : 0 Operand t = add(v, c); // t = v + c storeN(t, pz); // アドレスpzにtを書き込む 15 / 19
  16. 16. • bit=128, N=2のとき DLSから出力されたLLVMビットコード define void @mcl_fp_sub2L( i64* noalias %r1, i64* noalias %r2, i64* noalias %r3, i64* noalias %r4) { %r5 = load i64, i64* %r2 %r6 = zext i64 %r5 to i128 %r8 = getelementptr i64, i64* %r2, i32 1 %r9 = load i64, i64* %r8 %r10 = zext i64 %r9 to i128 %r11 = shl i128 %r10, 64 %r12 = or i128 %r6, %r11 %r13 = load i64, i64* %r3 %r14 = zext i64 %r13 to i128 %r16 = getelementptr i64, i64* %r3, i32 1 %r17 = load i64, i64* %r16 ... %r48 = getelementptr i64, i64* %r1, i32 1 %r49 = trunc i128 %r46 to i64 store i64 %r49, i64* %r48 mcl_fp_sub2L: movq (%rsi), %rax movq 8(%rsi), %r8 xorl %esi, %esi subq (%rdx), %rax sbbq 8(%rdx), %r8 movq %rax, (%rdi) movq %r8, 8(%rdi) sbbq $0, %rsi testb $1, %sil jne .carry retq .carry: movq 8(%rcx), %rdx addq (%rcx), %rax movq %rax, (%rdi) adcq %r8, %rdx movq %rdx, 8(%rdi) retq LLVMビットコード x64 asm 16 / 19
  17. 17. • JIT(実行時コード生成)の開発を補助するライブラリ • C++の文法でx64アセンブリ言語のDSLで記述可能 • CPUの特性に応じた処理の変更が可能 • Intel CPU向けに多倍演算をxbyakで実装 Xbyak // mulx命令が利用可能なら使う if (useMulx_) { mov(rdx, x); mulx(rax, t0, ptr [py]); mulx(rdx, x, ptr [py + 8]); add(x, rax); adc(rdx, 0); } else { // 古いCPUでの処理... mov(rax, ptr [py]); mul(x); ... 17 / 19
  18. 18. • x64(3.2GHz)とaarch64で測定(msec) • DSL for LLVMがGMPの1.8倍高速 • x64/aarch64用のアセンブリコードを1行も書いていない • 比較的抽象度の高い記述で高速なコードを開発できる • cf. relic-toolkit/relic(bb41dc88 ; preset/x64-pbc-bls12-381.sh) • pp/bench_ppのpp_map_oatep_k12 0.687msec ベンチマーク mode x64(64bit) aarch64 Xbyak 0.510 - DSL for LLVM 0.689 3.466 GMP 1.253 6.393 pure C++ 1.948 7.445 WebAssembly 5.98 20.16 18 / 19
  19. 19. • BLS署名の実装の紹介 • 複数署名の検証を行うmultVerifyのマルチコア向け実装 • LLVMビットコードを生成するDSLにより 有限体の四則演算を比較的高速に実装 • x64/aarch64でGMPの1.8倍 • WebAssembly向けのLLVMビットコードの改善 まとめ 19 / 19
  20. 20. backup 20 / 19
  21. 21. • 利点 • 柔軟なコード生成 • 欠点 • SELinuxやmacOSなどでJITを許可する設定が必要なことがある • Ethereumで利用するペアリングパラメータは固定 • mulx, adox, adcxなどの命令は利用すると仮定 • 古いCPUはLLVMやGMPによるコードにフォールバック • JITではなくxbyakを通常のアセンブラとして利用する • JITコードの静的化 JITコード 21 / 19
  22. 22. • 方法 • JIT生成したコードをバイナリダンプしてasmファイルに出力 • コンパイル時にそのファイルをリンクする • 考慮すべきこと • JIT codeは実行時にアドレスを解決し終える • static codeをリンクするときに異なるアドレスに配置される • 位置独立コードPICで動くようにJIT codeを修正する • global変数への参照に注意する JITコードの静的化 mcl JIT code 実行時コード生成 objファイル として保存 mcl' static code 通常のリンク 左と異なるアドレス 22 / 19
  23. 23. • ライブラリを他の言語から使えるようにすること • 実アプリケーション利用でのバインディングの知見の共有 • 動的メモリ確保は可能な限り避ける • C APIでは構造体を隠蔽するために不定型のvoid*をハンドルと して生成、処理、破棄を担当するAPIを用意することが多い • GC(ガベージコレクション)のある言語ではdestroyを呼ぶタ イミングが難しい • API内部で確保されるメモリはGCの管理外 言語バインディング struct SecretKey *sec = SecretKey_create(); // 内部でメモリ確保 SecretKey_init(sec); ... SecretKey_destroy(sec); // メモリ破棄 23 / 19
  24. 24. • 秘密鍵などのオブジェクトを固定長配列で用意する • データを呼び出す言語側で確保する • その領域の管理は言語に任される • GCの管理下になる • 確保された領域に対する操作APIを用意する 固定長配列 struct SecretKey { uint64_t d[6]; // 384ビット }; SecretKey sec; SecretKey_init(&sec); ... // 破棄操作不要 24 / 19
  25. 25. • objの配列 • シンプル • C側で処理が容易 • objの間に隙間(padding)がないように注意する必要あり • 呼び出す言語側の配列と対応しないことがある • その場合メモリコピーが必要 • objへのポインタ配列 • ポインタ配列を作る コストはobjの配列より 低い • Goのversionがあがるとポインタ配列は扱えなくなった ポインタ配列を使わない sec0 sec1 sec2... sec0 sec1 sec2... psec0 psec1 psec2... 25 / 19
  26. 26. • ブラウザ上で実行できる仮想マシン低水準言語 • Ethereumのスマートコントラクトの実行レイヤで利用予定 • 制約 • 標準ではmalloc/freeがない • C++では-ffreestanding -fno-exceptions -nodefaultlibs - nostdlib -fno-use-cxa-atexit -fno-unwind-tables -fno-rtti - nostdinc++でコンパイル出来るように開発 • wasmが扱うメモリ𝑀 𝑊とJavaScriptが扱うメモリ𝑀𝐽が異なる • データ保持の選択 • JavaScriptのクラスが𝑀𝐽を持つ • オブジェクトの寿命がきたときに手動で破棄する必要性 • JavaScriptプログラマには慣れないスタイルのため採用せず WebAssembly (wasm) 26 / 19
  27. 27. • JavaScript側ではUint32Arrayの配列を持ちwasmの関数 を呼ぶときに𝑀𝐽から𝑀 𝑊へメモリコピーをする • 不要なメモリコピーが発生するがメモリリークは発生しない 安全なデータ保持 Signature.add(y) { const xPos = this._allocAndCopy() // 𝑀 𝑊を確保し𝑀𝐽 → 𝑀 𝑊 const yPos = y._allocAndCopy() // 𝑀 𝑊′を確保し𝑀𝐽′ → 𝑀 𝑊′ mod.mcl_addSignature(xPos, yPos) // wasmのaddSignatureをcall _free(yPos) // 𝑀 𝑊 ′ を解放 this._saveAndFree(xPos) // 𝑀 𝑊 → 𝑀𝐽のあと𝑀 𝑊を解放 } sec:Uint32Array 𝑀 𝑊 JavaScript SecretKey Memory call wasm function 27 / 19

×