Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VOICEVOXコアのプロプライエタリ部分をonnxruntimeに逃がして別々にビルド可能にする #24

Open
Hiroshiba opened this issue Mar 27, 2023 · 12 comments · May be fixed by VOICEVOX/voicevox_core#825
Labels
優先度:低 機能向上 要議論 実行する前に議論が必要そうなもの

Comments

@Hiroshiba
Copy link
Member

Hiroshiba commented Mar 27, 2023

概要

今VOICEVOXのコードは大半がOSSですが、唯一コアのonnxモデル暗号化の部分だけがプロプライエタリになっています。
そのせいでコアはいくつかの問題が浮き彫りになっています。

  1. OSSのGithub Actionsでビルドできないためビルドリソースを気にしないといけない(月3,000分)
  2. プロプライエタリ部分のビルドでコケるるとヒホが解決するまで全体の進捗が止まる
  3. Android版やiOS版などの開発に手順が増えて手間
  4. 実は脆弱性がある

特に2つ目が厄介で、Rust化してからヒホの技量不足により足を引っ張ってしまい、OSS本来の力を出せていません。

そこで生まれたのが 暗号化部分(バイナリの変換)を全部onnxruntime内に逃がす という発想です。(thx @qryxip !)
これにより↑の1~4が全部解決し、特にOSS的には「専用のonnxruntimeライブラリさえ用意できればOSS版コアは独立に開発・バージョンアップできる」というかっこいい状態になります。

ちなみにキャラ追加部分は独立できないのですが、これはこちらで取り組み中です。(thx @qwerty2501 !)

手法

この「コアの製品版コードをonnxruntimeに逃がすプロジェクト」は大きく分けて3段階の工程があると思っていて、その工程ごとに人を募集したい感じです。

まず1つ目が「通常のonnxruntimeをGithub Actionsでビルドする」ことです。
Windows CPU/DirectML/CUDA、Mac CPU、Linux CPU/CUDAでのビルドが必要です。
ぶっちゃけここが一番難しい気がしています。

2つ目が「暗号化・復号化を組み込めるような関数を用意する」ことです。
これはload関数の中や外に復号化専用の経路を用意する必要があります。
ぶっちゃけここはこの発想に至ること自体は難しい一方、実装はある程度簡単な気がしています。

3つ目が製品部分、つまり暗号化・復号化処理です。
これはOSSではないため、秘匿コード開発専用のチームに参加して頂くことになります。
ここは難度が不明です。セキュリティ周り詳しい方がいたらぜひ意見聞きたいです。
成果物ができてもコードは公開できませんが、誰と一緒に作ったかはちゃんと公表させていただこうと思います。

その他

興味あれば 👀 リアクションなどいただければ・・・!

参考

Linux armhf版などのonnxruntimeをGithub Actions上でビルドしている例
https://github.com/VOICEVOX/onnxruntime-builder

Rustから直接VOICEVOX Coreを使いたい
VOICEVOX/voicevox_core#388

@Hiroshiba Hiroshiba added 優先度:低 機能向上 要議論 実行する前に議論が必要そうなもの labels Mar 27, 2023
@Hiroshiba
Copy link
Member Author

まず手を付け始められるのは1と、あと3もあります。
(暗号化周りはちょっとonnxruntime関係ないRust周りで困っているので、ご興味あればぜひ・・・ 😇 )

@qryxip
Copy link
Member

qryxip commented Mar 27, 2023

2つ目の「暗号化・復号化を組み込めるような関数を用意する」ですが、私が前試したときはまず

こういうRust
[profile.release]
opt-level = "z"
lto = true
codegen-units = 1
panic = "abort"
strip = true

[package]
name = "voicevox_decrypt"
version = "0.0.0"
edition = "2021"
publish = false

[lib]
crate-type = ["staticlib", "cdylib"]

[dependencies]
cxx = "1.0.91"
thiserror = "1.0.38"
use thiserror::Error;

#[cxx::bridge(namespace = "voicevox")]
mod ffi {
    extern "Rust" {
        pub fn decrypt_model(content: &[u8]) -> Result<Vec<u8>>;
    }
}

fn decrypt_model(content: &[u8]) -> Result<Vec<u8>, DecryptModelError> {
    Ok(content.to_owned())
}

#[derive(Error, Debug)]
#[error("Could not decrypt")]
struct DecryptModelError;

(追記) ついでなので zeroizeで囲ってもいいかも

でlibvoicevox_decrypt.aとvoicevox_decrypt.hを作って/voicevox_decryptに突っ込み、こうやってリンクしました。

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
index a5d28fb516..5582bf838f 100644
--- a/cmake/CMakeLists.txt
+++ b/cmake/CMakeLists.txt
@@ -966,6 +966,12 @@ function(onnxruntime_add_include_to_target dst_target)
     endforeach()
 endfunction()

+if(UNIX)
+  list(APPEND onnxruntime_EXTERNAL_LIBRARIES "${REPO_ROOT}/voicevox_decrypt/libvoicevox_decrypt.a")
+elseif(WIN32)
+  list(APPEND onnxruntime_EXTERNAL_LIBRARIES "${REPO_ROOT}/voicevox_decrypt/voicevox_decrypt.lib")
+endif()
+
 # ACL
 if (onnxruntime_USE_ACL OR onnxruntime_USE_ACL_1902 OR onnxruntime_USE_ACL_1905 OR onnxruntime_USE_ACL_1908 OR onnxruntime_USE_ACL_2002)
   set(onnxruntime_USE_ACL ON)

@Hiroshiba
Copy link
Member Author

なーーーるほどです!! 静的リンクは全く考えてませんでした。
全然知らないのですが、この関数を直に叩かれたりとか、そこのバイナリ解析されたりとかでなんか割とあっさり突破されそうなのかもとか思いました。
いやまあ、そんなこと言ってると大体どんな手法でもかなり弱い気もするのですが・・・ 😇

@Yosshi999
Copy link

Yosshi999 commented Mar 27, 2023

バイナリ解析まで視野に入れると基本的に防御は難しいと思います。推論時には復号済みのweightsがどこかに置いてある必要があり、そもそもユーザーは自分のマシンのメモリを見ることができるので
本気でやるならいわゆるアンチチートを入れることになるとおもいますが、ちょっとやりすぎな感じもあります

(バイナリ解析を妨害する技術もありますがあまり詳しくないです...)

@Hiroshiba
Copy link
Member Author

Hiroshiba commented Mar 27, 2023

まあそのあたりはここで議論しちゃうと・・・って感じかなと思いました。

できる範囲で考えると、暗号部分のコードやビルドコマンドを全部含めて秘匿しておいてactionsで実行、が一番強い気がしました。
となるとまあ2と3が合体した感じになるので2の工程が吹っ飛びますが。。

@Hiroshiba
Copy link
Member Author

議題の1つに、普通のonnxモデル(OSS内にあるもの)を読めるものと、製品版のonnxモデルを読めるものとで別のdllを用意する必要があってしまうという議論がありました。 (thx. @PickledChair !)

提案されているようにonnxruntimeを使う部分も外部ライブラリとして切り出す方法があると思います。
あるいは、onnxモデルを読む関数の引数にcrepted引数を用意して制御可能にする方法もあるかなと!

@Hiroshiba
Copy link
Member Author

Hiroshiba commented Apr 8, 2023

このタスク、そろそろ進めたい気持ちになってきました。
以前コアをC++からRustに移行したときに @PickledChair さんが作ってくださったようなタスクリストがとりあえずあると、もう始められるなという所感です。

(時間ができたらリスト作ろうと思いますが、もしご興味ある方いたら作ってくださるとすごく嬉しいです!!!!!)

@qryxip
Copy link
Member

qryxip commented Apr 10, 2023

思い付くままに書いてみようとしたのですが、細かいタスクリストに落とし込む前に方針の認識合わせが必要かと思いました。方針としてはDiscordとかで話したことから次のようになるかと思っているのですが、どうでしょうか?

  • VOICEVOX/voicevox_decryptをpublicに作り、またそのprivateなforkを用意する
    (VOICEVOXコアのプロプライエタリ部分をonnxruntimeに逃がして別々にビルド可能にする #24 (comment)のように作る)
    • 2人以上の暗号化部隊を結成する
    • 結成した暗号化部隊で、privateな方のリポジトリで復号化を実装 (流用?)し、publicな方とのdiffを.patchファイルとして得る (当然秘匿情報)
  • VOICEVOX/onnxruntime
  • onnxruntime-builder
    • Android/iOSも含め、全種類のonnxruntime v1.14.1(かそれ以降のバージョン)の動的ライブラリをビルドできるようにする (issue未作成)
      • Android (issue未作成)
      • Windows, macOS, Linux (issue未作成)
    • voicevox_decryptの.patchファイルをsecretとして登録。microsoft/onnxruntimeではなくVOICEVOX/onnxruntimeをcheckoutするようにし、 事故防止のため1> /dev/null 2> /dev/nullの状態で .patchを適用したvoicevox_decrypt.{h,lib}をビルドして使うようにする (こけたらエスパーでなんとかする)
  • VOICEVOX/onnxruntime-rs
    • VOICEVOX/onnxruntimeに依存する形でAPIを書き換える (encrypted引数の追加)
  • voicevox_core
    • 新クラス設計API voicevox_core#370
      (これをマージしないとCORE側で身動きが取れない)
    • VOICEVOX/onnxruntime-rsを更新し、暗号化部分を削除。このリポジトリでリリースビルドを行うようにする

あとVOICEVOX/voicevox_core#388ですが、正直VOICEVOXとしてはメリットが薄く、私個人のモチベーションに大きく左右されるかと思うので、であればここまでやってから気長にリリースという形にしたいなと思っています。

Rust API提供タスクリスト案
  • ONNX Runtime本体にマージされたRust実装を使う voicevox_core#427
    (Rustのクレートとして使う場合、これをしないと使い勝手に大きく影響する)
  • Rustdocを書く (issue未作成)
    • (注意点やコード例も含め、懇切丁寧に)
    • (日本語ではなく英語で書く選択肢もある。(Rustが普及して欲しい身としては悲しいことに)Rustを読み書きできる日本語話者には多分影響が無い。しかしずんだもん達が英語を話せない以上、非日本語話者に向けてアピールするメリットも薄くはある)
  • Crates.ioに自動またはアップロードする体制を議論する (issue未作成)
    • リポジトリの方のバージョンを0.0.0で固定する現在のスタイルと相性が悪いので、それを議論する
    • 二回目以降のバージョンをActionsからcargo publishする仕組みを整える
      (理由は省略するが、最初のバージョンだけは私(@qryxip)の名前で手元から手動でアップロードする)
  • 「ENGINEと同じことができる」と言えるよう、足りない機能を実装する
    (どうせやるなら良い第一印象を持ってもらえるようにする)

@Hiroshiba
Copy link
Member Author

なるほどです、そんな感じで進められると良いのかなと思いました!
ここから先は製品版暗号化開発チームを作ってそちらでprivateに進められると良さそうです。
(ちょっとお時間頂くかもです 🙇 )

Rust API提供タスクリスト案

こちらはこのissueと関係性が高くないので、関係性の高い VOICEVOX/voicevox_core#388 で書くのが適当なのかなと思いました!!

@sevenc-nanashi
Copy link
Member

APIにencrypted引数を追加する

(あまり暗号化とかに詳しくないのですが)
たとえば、ファイルの最初がVVEM(VoiceVox Encrypted Model)で始まってたら暗号化されていると判断&復号、みたいな感じにすると引数の変更がなくなって本家の追従とかがやりやすくなると思いました。

@Hiroshiba
Copy link
Member Author

たしかに引数がなくなると追従しやすそうですね!
もし引数追加で微妙な感じになったら引数なくしても良いかもと思いました。

@qryxip
Copy link
Member

qryxip commented Aug 30, 2024

qryxip pushed a commit to VOICEVOX/voicevox_core that referenced this issue Sep 29, 2024
頂いたコメントをもとに、自分でビルドした場合はサンプルモデルしか読み込め
ないことがわかるようにする。

#492 (comment)

実際は自分で作ったonnxモデルなども読み込めるといえば読み込めるため、「製
品版VOICEVOXのvvmは読み込めません。」の方が適切かもしれない。ただ
VOICEVOX/voicevox_project#24 を完遂したら不要になる一文であるため、あま
り考えすぎる必要もないということで元の文章からほとんど変わらない形を採用
した。

close #492
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
優先度:低 機能向上 要議論 実行する前に議論が必要そうなもの
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants