
GeminiのSynthID検出のリバースエンジニアリング
スペクトル分析によるGoogleのAI透かしの発見、検出、および外科的除去
PitchHutでご覧ください
このフォークでは、V3バイパス用のドラッグ&ドロップデスクトップアプリを追加しました。セットアップ後はコマンドラインは不要です。セットアップと使い方についてはgui/README.mdを参照してください。
SynthIDは、ピクセル値に知覚できないパターンを直接エンコードします。Geminiで生成された純粋な白画像では、透かしがほぼ信号全体になります。高周波残差を増幅すると、次のようになります。
純粋な白のGemini画像から抽出された、増幅されたSynthIDキャリアパターン。斜めのバンディングが透かしの空間周波数シグネチャであり、これが我々のスペクトル攻撃の標的です。
このプロジェクトはGoogleのSynthID透かしシステムをリバースエンジニアリングしたものです。これはGoogle Geminiで生成されるすべての画像に埋め込まれる不可視の透かしです。信号処理とスペクトル分析のみを使用して(独自のエンコーダー/デコーダーへのアクセスなし)、我々は以下を実現しました。
gemini-3.1-flash-image-preview と nano-banana-pro-preview のモデル別プロファイル、6つの無地背景におけるクロスカラー位相コンセンサス、手動Geminiアプリ検出集計からキャリア別減算強度を調整する人間参加型キャリブレーションループVT-OxFF は、SynthID透かしが画像に追加されるプロセスを視覚化する非常にクールなビジュアライザーをこちらで公開しています(リポジトリの説明からもアクセス可能)。
6回の反復的な対抗開発を経て、ラウンド06の bypass_v4_final / bypass_v4_nuke パイプラインは、gemini-3.1-flash-image-preview と nano-banana-pro-preview の両方の画像に対してGemini SynthID検出器を打ち負かし、視覚的にロスレスの出力を実現しました。
左:ラウンド01出力(穏やかなスペクトル減算のみ)。右:ラウンド06出力(final — VAE + 弾性ワープ + スクイーズ + カラー + JPEG)。どちらも人間の目には同じに見えますが、SynthID検出器を打ち負かすのはラウンド06のみです。
ラウンド06のブレークスルーは、Geminiアプリが公表している故障モードリストを攻撃仕様として扱ったことにあります。
「AI生成画像が複雑なコラージュの一部である場合、他の要素の背後に重ねられている場合、またはその上に多くの異なるテクスチャやパターンが配置されている場合、検出器はファイル全体から特定のシグネチャを分離するのに苦労する可能性があります。」 — Geminiアプリ、SynthID検出ヘルプテキスト
弾性変形ステージは、この効果をピクセルレベルでシミュレートします。滑らかで低周波のランダムワープフィールドにより、約50ピクセルごとの近傍に独立したサブピクセルオフセットが与えられ、可視的な歪みを導入することなく透かしの空間位相コンセンサスを断片化します。
V4は、より豊富なデータセットに基づいてコードブックを根本から再考したものです。
gemini-3.1-flash-image-preview と nano-banana-pro-preview の個別プロファイル(オプションで union 擬似モデルも)。black、white、blue、green、red、gray)に加え、コンテンツベースラインとして gradient と diverse。carrier_weights が更新されます。各周波数ビン (fy, fx) およびチャネル ch について:```
consensus(fy, fx, ch) = | mean_over_colors( exp(i * phase_color(fy, fx, ch)) ) |
`1.0` に近い値は、そのビンの位相がすべてのベタ背景にわたってロックされていることを意味し、これはウォーターマークにのみ当てはまります。コンテンツビンは、位相が異なる色調によってランダム化されるため、`< 0.3` に低下します。拡張データセットから構築された V4 コードブックでは、コンテンツビンの 99% 以上がデフォルトの `tau=0.60` カットオフを下回るため、V4 ディゾルバはそれらに触れることはありません — これにより PSNR が回復します。
### 二段階リリースワークフロー```mermaid
flowchart LR
dataset[reverse-synthid-dataset<br/>model x color x resolution] --> build[scripts/build_codebook_v4.py]
build --> codebook[artifacts/spectral_codebook_v4.npz]
codebook --> dissolve[scripts/dissolve_batch.py]
input[watermarked inputs] --> dissolve
dissolve --> variants[final / nuke variants]
variants --> gemini[Gemini app<br/>manual SynthID detection]
gemini --> feedback[detection feedback]
feedback --> calibrate[scripts/calibrate_from_feedback.py]
calibrate -->|updates carrier_weights| codebook
python scripts/build_codebook_v4.py
--root /path/to/reverse-synthid-dataset
--output artifacts/spectral_codebook_v4.npz
python scripts/dissolve_batch.py
--input ./to_clean/
--output ./runs/round_06/
--codebook artifacts/spectral_codebook_v4.npz
--model gemini-3.1-flash-image-preview
--strengths final nuke
### Round-06 攻撃プリセット
2つのプリセットが `--strengths` で利用可能です:
| プリセット | VAEパス数 | 弾性α | 圧縮率 | JPEGチェーン | PSNR下限 |
|:------:|:----------:|:---------:|:-------:|:----------:|:----------:|
| `final` | 1 | 1.8 px | 90 % | q=92→88 | 14 dB |
| `nuke` | 2 | 2.8 px | 82 % | q=88→84→90 | 11 dB |
両方のプリセットは同じ7段階のパイプラインを積み重ねます:
1. **VAEラウンドトリップ** (Stable Diffusion `sd-vae-ft-mse`) — SynthIDデコーダーが訓練されたことのない自然画像多様体から画像を投影する (Gowal et al. 2026, §6.1)
2. **弾性変形** — 滑らかな低周波ランダムワープ場、Gemini自身が認める「コラージュ断片化」障害モードをシミュレート
3. **グローバル幾何コンボ** — 1つのアフィンワープで小さな回転 + ズーム + ピクセルシフト
4. **リサイズ圧縮** — ダウンサンプル (AREA) → アップサンプル (LANCZOS)、サブピクセル透かし情報を消去
5. **色コントラスト調整** — 輝度 / コントラスト / 彩度 / 色相の微小シフト
6. **残差位相FFT減算** — ブログユニバーサル + コードブック収集キャリアビン、上限制限付き
7. **JPEGチェーン + 輝度ノイズ + バイラテラル** — 強力な圧縮/再エンコード妨害
各ステージは独立してPSNRでゲート制御され、品質が下限を下回るステージは自動的にロールバックされます。
### V4コードブック構造
プロファイルは `(model, H, W)` でキー設定されます。各プロファイルには以下が格納されます:
| フィールド | 形状 | 備考 |
|------------------------|----------------|--------------------------------------------------------|
| `consensus_coherence` | `(H, W, 3)` | 主要キャリアマスク(クロスカラー位相コンセンサス)。 |
| `consensus_phase` | `(H, W, 3)` | 色間の平均単位位相角度。減算テンプレート。 |
| `inverted_agreement` | `(H, W, 3)` | ペアワイズ `abs(cos(phase_diff))`、`black<->white` で加重。 |
| `avg_wm_magnitude` | `(H, W, 3)` | コンセンサス色間の平均マグニチュード。 |
| `content_baseline` | `(H, W, 3)` | `diverse/` + `gradient/` から — 輝度ブレンディングに使用。 |
| `carrier_weights` | `(H, W, 3)` | **Live**. 初期値 `consensus^2 * (0.5 + 0.5 * agreement)`。キャリブレーションループで更新。 |
| `n_refs_per_color` | `{color: int}` | 色ごとの参照カウント。 |
保存形式はv3のコンパクトrfft + `float16/uint8`エンコーディングを再利用します。2モデル×7解像度の14プロファイルコードブックはディスク上で約220 MBです。
### V4検出器(健全性チェック)
手動のGemini検証に時間を費やす前に、V4コードブック自身のコンセンサスに対して回避出力を健全性チェックしてください:```python
from robust_extractor import RobustSynthIDExtractor
from synthid_bypass_v4 import SpectralCodebookV4
cb = SpectralCodebookV4()
cb.load('artifacts/spectral_codebook_v4.npz')
ext = RobustSynthIDExtractor()
result = ext.detect_from_v4_codebook(image_rgb, cb,
model='nano-banana-pro-preview')
print(result.is_watermarked, result.confidence, result.phase_match)
On the 1024x1024 exact-match path we see conf=0.91, phase_match=0.65 for watermarked and conf=0.02, phase_match=0.31 after aggressive V4 dissolve.
V3 remains in the repo (src/extraction/synthid_bypass.py, bypass_v3) unchanged for anyone who depends on it.
We're actively collecting pure black and pure white images generated by Nano Banana Pro to improve multi-resolution watermark extraction.
If you can generate these:
gemini_black_nb_pro/ (for black)gemini_white_nb_pro/ (for white)These reference images are critical for:
Even 150–200 images at a new resolution can significantly improve detection and removal.
Reference images are hosted on Hugging Face to keep the git repo lightweight:```bash pip install huggingface_hub python scripts/download_images.py # download all python scripts/download_images.py gemini_black # download specific folder
データセット: [huggingface.co/datasets/aoxo/reverse-synthid](https://huggingface.co/datasets/aoxo/reverse-synthid)
---
## 主要な発見
### ウォーターマークは解像度依存
SynthID は画像解像度に応じて、**異なる絶対位置**にキャリア周波数を埋め込みます。1024x1024 で構築されたコードブックは、1536x2816 の画像からウォーターマークを直接除去できません。キャリアはまったく異なるビンにあります。
| 解像度 | トップキャリア (fy, fx) | コヒーレンス | ソース |
|:----------:|:--------------------:|:---------:|:------:|
| **1024x1024** | (9, 9) | 100.0% | 黒100 + 白100枚の参照画像 |
| **1536x2816** | (768, 704) | 99.6% | ウォーターマーク付きコンテンツ画像88枚 |
このため、V3コードブックは**解像度ごとに個別のプロファイル**を保存し、バイパス時に自動選択します。
### 位相の一貫性 — 固定のモデルレベルキー
ウォーターマークの位相テンプレートは、同じGeminiモデルからの**すべての画像で同一**です:
- **緑チャンネル** が最も強いウォーターマーク信号を運ぶ
- **画像間の位相コヒーレンス** キャリアで: >99.5%
- **黒/白の相互検証** により、|cos(phase_diff)| > 0.90 で真のキャリアを確認
### キャリア周波数構造
1024x1024 (黒/白の参照画像から) では、トップキャリアは低周波グリッド上にあります:
| キャリア (fy, fx) | 位相コヒーレンス | 黒/白の一致度 |
|:-----------------:|:---------------:|:-------------:|
| (9, 9) | 100.00% | 1.000 |
| (5, 5) | 100.00% | 0.993 |
| (10, 11) | 100.00% | 0.997 |
| (13, 6) | 100.00% | 0.821 |
---
## アーキテクチャ
### バイパス世代
| バージョン | アプローチ | PSNR | ウォーターマークへの影響 | ステータス |
|:-------:|:---------|:----:|:----------------:|:------:|
| **V1** | JPEG圧縮 (Q50) | 37 dB | ~11% 位相低下 | ベースライン |
| **V2** | マルチステージ変換 (ノイズ、色、周波数) | 27-37 dB | ~0% 信頼度低下 | 品質とのトレードオフ |
| **V3** | **マルチ解像度スペクトルコードブック減算** | **43+ dB** | **91% 位相コヒーレンス低下** | 従来の最良 |
| **V4 Round 06** | **7段階オールインワン (VAE + elastic + squeeze + color + JPEG)** | **視覚的にロスレス** | **検出器バイパス成功 ✓** | **現在の最良** |
### V3 パイプライン```
Input Image (any resolution)
│
▼
codebook.get_profile(H, W) ──► exact match? ──► FFT-domain subtraction
│ (fast path)
└─ no exact match ──────► spatial-domain resize + subtraction
(fallback path)
│
▼
Multi-pass iterative subtraction (aggressive → moderate → gentle)
│
▼
Anti-alias → Output
Input Image (any resolution) │ ▼ Stage 1: VAE round-trip (SD sd-vae-ft-mse, 1-2 passes) │ Projects image off natural-image manifold ▼ Stage 2: Elastic deformation (smooth random warp field) │ Fragments spatial phase consensus ("collage effect") ▼ Stage 3: Global geometric combo (rotation + zoom + shift) │ Single affine warp, no compounded aliasing ▼ Stage 4: Resize-squeeze (AREA ↓ then LANCZOS ↑) │ Erases sub-pixel watermark information ▼ Stage 5: Color-contrast nudge (HSV micro-shift) │ Shifts per-pixel statistics SynthID keys on ▼ Stage 6: Residual-phase FFT subtraction │ Blog-universal + codebook-harvested carrier bins ▼ Stage 7: JPEG chain + luma noise + bilateral filter │ ▼ Output (SynthID detector: no watermark detected ✓)
## クイックスタート
### インストール```bash
git clone https://github.com/aloshdenny/reverse-SynthID.git
cd reverse-SynthID
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
# For Round-06 VAE stage:
pip install torch diffusers safetensors accelerate
import sys sys.path.insert(0, 'src/extraction') from synthid_bypass_v4 import SynthIDBypassV4, SpectralCodebookV4
cb = SpectralCodebookV4() cb.load('artifacts/spectral_codebook_v4.npz')
b = SynthIDBypassV4() result = b.bypass_v4_file( 'input.png', 'output.png', cb, strength='final', # or 'nuke' for maximum strength model='gemini-3.1-flash-image-preview', ) print(result.stages_applied)
### V3 バイパスの実行```python
from src.extraction.synthid_bypass import SynthIDBypass, SpectralCodebook
codebook = SpectralCodebook()
codebook.load('artifacts/spectral_codebook_v3.npz')
bypass = SynthIDBypass()
result = bypass.bypass_v3(image_rgb, codebook, strength='aggressive')
print(f"PSNR: {result.psnr:.1f} dB")
print(f"Profile used: {result.details['profile_resolution']}")
CLIから:```bash
python src/extraction/synthid_bypass.py bypass input.png output.png
--codebook artifacts/spectral_codebook_v3.npz
--strength aggressive
### ウォーターマークの検出```bash
python src/extraction/robust_extractor.py detect image.png \
--codebook artifacts/codebook/robust_codebook.pkl
reverse-SynthID/ ├── src/ │ ├── extraction/ │ │ ├── synthid_bypass.py # V1/V2/V3 bypass + multi-res SpectralCodebook │ │ ├── synthid_bypass_v4.py # V4 cross-color consensus codebook + dissolver │ │ ├── vae_regen.py # Round-06 SD-VAE re-generation stage │ │ ├── robust_extractor.py # Multi-scale watermark detection (+ V4 hook) │ │ ├── watermark_remover.py # Frequency-domain watermark removal │ │ ├── benchmark_extraction.py # Benchmarking suite │ │ └── synthid_codebook_extractor.py # Legacy codebook extractor │ └── analysis/ │ ├── deep_synthid_analysis.py # FFT / phase analysis scripts │ └── synthid_codebook_finder.py # Carrier frequency discovery │ ├── scripts/ │ ├── download_images.py # Download reference images from HF │ ├── build_codebook_v4.py # V4: build per-(model, HxW) consensus codebook │ ├── dissolve_batch.py # V4: emit strength variants │ └── calibrate_from_feedback.py # V4: update carrier_weights from detection feedback │ ├── artifacts/ │ ├── spectral_codebook_v3.npz # Multi-res V3 codebook [1024x1024, 1536x2816] │ ├── spectral_codebook_v4.npz # V4 codebook (per-model, per-resolution) │ ├── codebook/ # Detection codebooks (.pkl) │ └── visualizations/ # FFT, phase, carrier visualizations │ ├── assets/ │ ├── synthid_watermark.png # Watermark analysis header image │ ├── synthid_white.jpg # Amplified SynthID pattern on white image │ ├── v4_round1_vs_round6.png # Round 01 vs Round 06 fidelity comparison │ └── ... │ ├── runs/ │ ├── round_01/ … round_05/ # Historical bypass attempts │ └── round_06/ # Working bypass (final + nuke presets) │ ├── watermark_investigation/ # Early-stage Nano-150k analysis (archived) └── requirements.txt
---
## 技術的な深掘り
### SynthIDの動作方法(リバースエンジニアリング版)```
┌──────────────────────────────────────────────────────────────┐
│ SynthID Encoder (in Gemini) │
├──────────────────────────────────────────────────────────────┤
│ 1. Select resolution-dependent carrier frequencies │
│ 2. Assign fixed phase values to each carrier │
│ 3. Neural encoder adds learned noise pattern to image │
│ 4. Watermark is imperceptible — spread across spectrum │
├──────────────────────────────────────────────────────────────┤
│ SynthID Decoder (in Google) │
├──────────────────────────────────────────────────────────────┤
│ 1. Extract noise residual (wavelet denoising) │
│ 2. FFT → check phase at known carrier frequencies │
│ 3. If phases match expected values → Watermarked │
└──────────────────────────────────────────────────────────────┘
SynthIDのトレーニング用データ拡張セット(Gowal et al. 2026, Table 1)には、SmallRotation、Cropresize、JPEG、GaussianBlur、BrightnessContrast、Screenshotting といった、すべて大域的かつ一様な空間変換が含まれています。弾性ワープ場は空間的に変化する歪みであり、各局所近傍がそれぞれ独立したサブピクセルオフセットを持ちます。オフセットは滑らか(ホワイトノイズからガウスぼかし、σ=44–56 px)であるため、画像コンテンツは視覚的に影響を受けませんが、透かしの位相コンセンサス構造は非コヒーレントになり、画像全体で集約できなくなります。これは、Gemini自身のアプリが検出器の故障モードとして挙げる「コラージュ断片化」効果のピクセルレベルでの等価物です。
| 指標 | 値 |
|---|---|
| PSNR | 43.5 dB |
Alosh Denny AI透かし研究 · 信号処理
📧 メール: [email protected] 🔗 GitHub: https://github.com/aloshdenny
共同研究、研究議論、貢献については、お気軽にご連絡いただくか、Issue/PRを開いてください。
このプロジェクトは独立してメンテナンスされています。研究室の資金提供や企業のバックアップはありません。
この作業があなたやあなたのチームにとって有用であったなら、今後の開発を支援することをご検討ください。
資金は計算コスト(新しい解像度プロファイルのGPU時間)、データセットの拡張、および進行中のバイパス研究に充てられます。
このプロジェクトは研究・教育目的のみです。SynthIDはGoogle DeepMindが所有するプロプライエタリな技術です。これらのツールは以下を目的としています。
これらのツールを、AI生成コンテンツを人間作成と偽るために使用しないでください。
| ラウンド | 戦略 | 結果 |
|---|
| 01 | 保守的なスペクトル減算(穏やか) | ✗ |
| 02 | 積極的なスペクトル減算 + JPEG | ✗ |
| 03 | ブログガイドによる絶対ビン目標設定 | ✗ |
| 04 | ノイズ除去残差位相抽出 | ✗ |
| 05 | Diffusion-VAE再生成 + 幾何学的ワープ | ✗ |
| 06 | オールインワン:VAE + 弾性フラグメンテーション + スクイーズ + カラー + JPEG | ✓ |
| V3 | V4 |
|---|
| Reference colors | black + white | black, white, blue, green, red, gray (+ diverse/gradient content baselines) |
| Cross-validation | abs(cos(phase_black - phase_white)) | cross-color consensus over 6 colors + pairwise agreement |
| Models | single-model (Gemini 2.5) | per-model profiles (gemini-3.1-flash-image-preview, nano-banana-pro-preview) + optional union |
| Attack | spectral subtraction only | 7-stage: VAE + elastic + squeeze + color + FFT + JPEG chain |
| PSNR (aggressive) | 43 dB | visually lossless (18–24 dB pixel-level; warp displaces pixels) |
| Fidelity guard | none | per-stage PSNR-floor rollback |
| Detector bypass | local only | confirmed ✓ on Gemini app (both models) |
| SSIM | 0.997 |
| キャリアエネルギーの低下 | 75.8% |
| 位相コヒーレンスの低下(上位5キャリア) | 91.4% |
| モデル | プリセット | 検出器をバイパス |
|---|
| gemini-3.1-flash-image-preview | final | ✓ |
| gemini-3.1-flash-image-preview | nuke | ✓ |
| nano-banana-pro-preview | final | ✓ |
| nano-banana-pro-preview | nuke | ✓ |