
研究専用AIウォーターマーク堅牢性ツールキット:ローカルリバースプロキシがC2PA/EXIF/XMP、Unicode、画像/音声ステゴ、OOXML/PDFメタデータを除去し、Trojan Sourceをスキャンする。
ユニバーサルAI由来・透かしサニタイゼーションミドルウェア 研究用アーティファクト — 透かしロバスト性評価専用。
NullOrigin は研究用アーティファクトです。透かしロバスト性に関する学術的・独立的な研究を支援するために公開されており、それ以外の目的はありません。
透かし方式はセキュリティ上の主張であり、セキュリティ上の主張は、誰かがそれを破ろうと試みて初めて意味を持ちます。このプロジェクトが実装する文献 — KGW に関する Kirchenbauer ら、パラフレーズ攻撃に関する Krishna ら、Trojan Source に関する Boucher & Anderson — は、研究者が実際に動作する攻撃を公開し、防御側が想定ではなく現実のロバスト性を測定できるようにしたからこそ存在します。このリポジトリが属するのは、そうした伝統です。
意図された用途
意図されておらず、サポートもされない用途
ここに記載されているのは、コードの実行方法に関する技術的制御ではありません。本ソフトウェアが提供される条件と、その作者がサポートする/しないことの表明です。本ソフトウェアは、いかなる種類の保証もなく**「AS IS」(現状のまま)**で提供されます — LICENSE を参照してください。
このツールが出力する数値から何らかの結論を導く前に、範囲と誠実な限界をお読みください。 対象とする方式のいくつかは公開されている検出器では検証できません。README は、それを暗に示すのではなく明言しています。
このツールが出力する数値から結論を導く前に、これを読んでください。
| レイヤー | 実際の動作 |
|---|---|
| 不可視文字 | 完全に有効。 ゼロ幅文字、双方向制御文字、変異選択子、Unicode Tags ブロックのペイロードは完全に除去され、その数が報告されます。異なるスクリプト間のホモグリフ紛らわし文字(キリル文字/ギリシャ文字が ASCII として描画されるもの)は畳み込まれます。 |
| 文書メタデータ (.docx) | 完全に有効。 docProps から作成者、最終編集者、リビジョン数、タイムスタンプ、テンプレート、アプリケーションのバージョンが消去され、書式はバイト単位で保持されます。 |
| C2PA / EXIF / XMP | 完全に有効。 画像は生のピクセルサンプルから新しいコンテナとして再構築されるため、署名付き JUMBF マニフェストとすべてのメタデータが消去されます。タグ付きフィクスチャに対するテストで検証済み。 |
| KGW 統計透かし | 書き換えバックエンドに完全に依存します。 ローカルモデルが設定されていない場合、統計透かしは生き残ります — このツールは、それを暗に示すのではなく明言します。 |
| SynthID-Text / SynthID-Image / Tree-Ring | ここでは検証できません。 これらは秘密鍵とプロプライエタリなデコーダを使用します。NullOrigin は文献に記載された摂動を適用しますが、実際の検出器を無効化するという主張は一切しません。比較測定できる公開検出器が存在しないためです。 |
| AudioSeal / SynthID-Audio | ここでは検証できません。理由は同じです。 |
KGWStatisticalDetector は、Kirchenbauer らによる空白トークン上の green/red リスト方式を数学的に忠実に、かつ自己整合的に実装したものです。これは、いかなるベンダーの本番透かしのデコーダでもありません。そうしたデコーダは秘密鍵とモデル独自の BPE 語彙に依存します。
その目的は、ベンチマークを現実のものにすることです。KGWWatermarkEmbedder が本物の透かしを埋め込み、パイプラインがそれを攻撃し、対応する検出器が実際の低減量を測定します。これはこの方式に対する攻撃の真の測定です。ベンダーの透かしには適用できません。
語彙 $V$ は、各ステップ $t$ において、直前の文脈をシードとしたハッシュによって分割されます:
$$s_t = \text{Hash}(w_{t-k}, \dots, w_{t-1})$$
サイズ $\gamma|V|$ の green リスト $G_t$ と red リスト $R_t$ に分割されます。green ロジットにはバイアス $\delta > 0$ が加算されます:
$$\tilde{l}{t,v} = \begin{cases} l{t,v} + \delta, & v \in G_t \\ l_{t,v}, & v \in R_t \end{cases}$$
検出は green ヒットを数えます。$H_0$ の下では $\text{Binomial}(T, \gamma)$ に従うため、次式になります:
$$z = \frac{|S_G| - \gamma T}{\sqrt{T\gamma(1-\gamma)}}$$
$z > 4.0$($p < 3\times10^{-5}$)の場合、合成と判定されます。
なぜパラフレーズが攻撃になるのか: 透かしは完全に局所的な n-gram 遷移の中に存在します。透かしのないモデルで表層形を書き換えると、すべての位置が再シードされます。これは透かし文献における標準的なロバスト性攻撃です。
なぜ長さが重要なのか: $z$ は $\sqrt{T}$ に比例して増大します。green 割合 0.70 の 100 トークンの文章では $z \approx 3.9$ にしか達しません — 閾値未満です。検出には数百トークンが必要であり、意味のあるベンチマークフィクスチャにも同様に数百トークンが必要です。
APP11 セグメント、PNG の tEXt/iTXt チャンク、または WebP/AVIF の c2pa ボックス内にある署名付きマニフェスト。署名はピクセルデータを対象としているため、素のサンプルバッファから再エンコードすれば、JUMBF を一切解析せずに除去できます。閾値以下の位相変調と低振幅のスペクトル付加です。音声基本周波数より上の位相ランダム化、非臨界帯域におけるバンドストップ・ノッチのシフト、心理音響的再量子化によって攻撃します。
| Python | 3.10、3.11、または 3.12 |
| OS | Linux、macOS(Intel および Apple Silicon)、WSL2 経由の Windows |
| 任意 | Ollama または OpenAI 互換サーバー — テキストの透かし除去に必要 |
| 任意 | Compose v2 を備えた Docker 20.10+ |
git clone https://github.com/rakib-nyc/nullorigin.git cd nullorigin
python -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e .
### オプションの追加機能```bash
pip install -e ".[dev]" # pytest, pytest-asyncio, ruff — needed to run the tests
pip install -e ".[nli]" # torch + sentence-transformers, for the fidelity gate
pip install -e ".[metrics]" # torch, transformers, sentence-transformers
pip install -e ".[llama]" # llama-cpp-python for in-process GGUF inference
pip install -e ".[dev,metrics]"
[nli]がない場合、フィデリティゲートは不変条件のみで動作します — それでも実際のチェックではありますが、 ロールの入れ替えには気づきません。セマンティック・フィデリティ を参照してください。
nullorigin --version nullorigin --help pytest -q # requires the [dev] extra
---
## 🚀 クイックスタート
### 1. ローカル書き換えモデルをセットアップする
テキストの透かし除去には、透かしのないローカルモデルが必要です。それがない場合、NullOriginは不可視文字を削除しますが、
**統計的透かしはそのまま残ります** — そして、その旨を明示します。```bash
ollama serve # in a separate terminal
ollama pull llama3.2:3b # or any instruct model you prefer
別のモデルを使用していますか?NullOrigin をそれに向けてください:```bash export NULLORIGIN_PARAPHRASER_MODEL=qwen3:4b export NULLORIGIN_PARAPHRASER_TIMEOUT=900 # reasoning models are slow
### 2. プロキシを起動する```bash
nullorigin run
Input content is missing — the chunk to translate was not included after "INPUT:". Please provide the source text for chunk 13 of 59.```console NullOrigin 1.0.0 — proxy listening on 127.0.0.1:8080 providers: anthropic, gemini, openai text engine: unicode=True backend=ollama media: metadata=True stego=True telemetry: open (loopback) health: http://127.0.0.1:8080/health
### 3. クライアントをその宛先に向ける```python
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8080/v1", api_key="your-upstream-api-key")
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Write an essay about privacy."}],
extra_headers={"x-nullorigin-provider": "openai"},
)
print(response.choices[0].message.content)
Anthropic:```python from anthropic import Anthropic