Back Original

Reverse engineering Gemini's SynthID detection

SynthID Watermark Analysis

Discovering, detecting, and surgically removing Google's AI watermark through spectral analysis

Visit us on PitchHut

Python License Detection V3 Bypass Phase Drop


This project reverse-engineers Google's SynthID watermarking system - the invisible watermark embedded into every image generated by Google Gemini. Using only signal processing and spectral analysis (no access to the proprietary encoder/decoder), we:

  1. Discovered the watermark's resolution-dependent carrier frequency structure
  2. Built a detector that identifies SynthID watermarks with 90% accuracy
  3. Developed a multi-resolution spectral bypass (V3) that achieves 75% carrier energy drop, 91% phase coherence drop, and 43+ dB PSNR on any image resolution

๐Ÿšจ Contributors Wanted: Help Expand the Codebook

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:

  • Resolution: any (higher variety = better)
  • Content: fully black (#000000) or fully white (#FFFFFF)
  • Source: Nano Banana Pro outputs only
  1. Generate a batch of black/white images by attaching a pure black/white image into Gemini and prompting it to "recreate this as it is"
  2. Place them in new folders:
    • gemini_black_nb_pro/ (for black)
    • gemini_white_nb_pro/ (for white)
  3. Open a Pull Request ๐Ÿš€

These reference images are critical for:

  • Carrier frequency discovery
  • Phase validation
  • Improving cross-resolution robustness

Even 150โ€“200 images at a new resolution can significantly improve detection and removal.


What Makes This Different

Unlike brute-force approaches (JPEG compression, noise injection), our V3 bypass uses a multi-resolution SpectralCodebook - a collection of per-resolution watermark fingerprints stored in a single file. At bypass time, the codebook auto-selects the matching resolution profile, enabling surgical frequency-bin-level removal on any image size.


The Watermark is Resolution-Dependent

SynthID embeds carrier frequencies at different absolute positions depending on image resolution. A codebook built at 1024x1024 cannot directly remove the watermark from a 1536x2816 image - the carriers are at completely different bins.

Resolution Top Carrier (fy, fx) Coherence Source
1024x1024 (9, 9) 100.0% 100 black + 100 white refs
1536x2816 (768, 704) 99.6% 88 watermarked content images

This is why the V3 codebook stores separate profiles per resolution and auto-selects at bypass time.

Phase Consistency - A Fixed Model-Level Key

The watermark's phase template is identical across all images from the same Gemini model:

  • Green channel carries the strongest watermark signal
  • Cross-image phase coherence at carriers: >99.5%
  • Black/white cross-validation confirms true carriers via |cos(phase_diff)| > 0.90

Carrier Frequency Structure

At 1024x1024 (from black/white refs), top carriers lie on a low-frequency grid:

Carrier (fy, fx) Phase Coherence B/W Agreement
(9, 9) 100.00% 1.000
(5, 5) 100.00% 0.993
(10, 11) 100.00% 0.997
(13, 6) 100.00% 0.821

At 1536x2816 (from random watermarked content), carriers are at much higher frequencies:

Carrier (fy, fx) Phase Coherence
(768, 704) 99.55%
(672, 1056) 97.46%
(480, 1408) 96.55%
(384, 1408) 95.86%

Three Generations of Bypass

Version Approach PSNR Watermark Impact Status
V1 JPEG compression (Q50) 37 dB ~11% phase drop Baseline
V2 Multi-stage transforms (noise, color, frequency) 27-37 dB ~0% confidence drop Quality trade-off
V3 Multi-resolution spectral codebook subtraction 43+ dB 91% phase coherence drop Best

V3 Pipeline (Multi-Resolution Spectral Bypass)

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
  1. SpectralCodebook stores resolution-specific profiles (carrier positions, magnitudes, phases)
  2. Auto resolution selection picks the exact profile or the closest match
  3. Direct known-signal subtraction weighted by phase consistency and cross-validation confidence
  4. Multi-pass schedule catches residual watermark energy missed by previous passes
  5. Per-channel weighting (G=1.0, R=0.85, B=0.70) matches SynthID's embedding strength

Results (V3 on 88 Gemini Images)

Aggregate Metrics (1536x2816, aggressive strength)

Metric Value
PSNR 43.5 dB
SSIM 0.997
Carrier energy drop 75.8%
Phase coherence drop (top-5 carriers) 91.4%

Quality Across Resolutions

Resolution Match PSNR SSIM
1536x2816 exact 44.9 dB 0.996
1024x1024 exact 39.8 dB 0.977
768x1024 fallback 40.6 dB 0.994

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

1. Build Multi-Resolution Codebook

From the CLI:

python src/extraction/synthid_bypass.py build-codebook \
    --black gemini_black \
    --white gemini_white \
    --watermarked gemini_random \
    --output artifacts/spectral_codebook_v3.npz

Or from Python:

from src.extraction.synthid_bypass import SpectralCodebook

codebook = SpectralCodebook()

# Profile 1: from black/white reference images (1024x1024)
codebook.extract_from_references(
    black_dir='gemini_black',
    white_dir='gemini_white',
)

# Profile 2: from watermarked content images (1536x2816)
codebook.build_from_watermarked('gemini_random')

codebook.save('artifacts/spectral_codebook_v3.npz')
# Saved with profiles: [1024x1024, 1536x2816]

2. Run V3 Bypass (Any Resolution)

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']}")
print(f"Exact match: {result.details['exact_match']}")

From the CLI:

python src/extraction/synthid_bypass.py bypass input.png output.png \
    --codebook artifacts/spectral_codebook_v3.npz \
    --strength aggressive

Strength levels: gentle (minimal, ~45 dB) > moderate > aggressive (recommended) > maximum

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
โ”‚   โ”‚   โ”œโ”€โ”€ robust_extractor.py            # Multi-scale watermark detection
โ”‚   โ”‚   โ”œโ”€โ”€ 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
โ”‚
โ”œโ”€โ”€ gemini_black/                          # 100 pure-black Gemini images (1024x1024)
โ”œโ”€โ”€ gemini_white/                          # 100 pure-white Gemini images (1024x1024)
โ”œโ”€โ”€ gemini_random/                         # 88 watermarked content images (1536x2816)
โ”‚
โ”œโ”€โ”€ artifacts/
โ”‚   โ”œโ”€โ”€ spectral_codebook_v3.npz           # Multi-res V3 codebook [1024x1024, 1536x2816]
โ”‚   โ”œโ”€โ”€ codebook/                          # Detection codebooks (.pkl)
โ”‚   โ””โ”€โ”€ visualizations/                    # FFT, phase, carrier visualizations
โ”‚
โ”œโ”€โ”€ assets/                                # README images and early analysis artifacts
โ”œโ”€โ”€ watermark_investigation/               # Early-stage Nano-150k analysis (archived)
โ””โ”€โ”€ requirements.txt

How SynthID Works (Reverse-Engineered)

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                  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            โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Multi-Resolution SpectralCodebook

The codebook captures watermark profiles at each available resolution:

  • 1024x1024 profile: from 100 black + 100 white pure-color Gemini outputs
    • Black images: watermark is nearly the entire pixel content
    • White images (inverted): confirms carriers via cross-validation
    • Black/white agreement (|cos(phase_diff)|) filters out generation bias
  • 1536x2816 profile: from 88 diverse watermarked content images
    • Content averages out across images; fixed watermark survives in phase coherence
    • Watermark magnitude estimated as avg_mag x coherence^2

The bypass uses direct known-signal subtraction (not a Wiener filter):

  1. Confidence = phase_consistency x cross_validation_agreement
  2. DC exclusion โ€” soft ramp suppresses low-frequency generation biases
  3. Per-bin subtraction = wm_magnitude x confidence x removal_fraction x channel_weight
  4. Safety cap โ€” subtraction never exceeds 90-95% of the image's energy at any bin
  5. Multi-pass โ€” decreasing-strength schedule (aggressive โ†’ moderate โ†’ gentle) catches residual energy

SpectralCodebook โ€” multi-resolution watermark fingerprint:

codebook = SpectralCodebook()
codebook.extract_from_references('gemini_black', 'gemini_white')  # adds 1024x1024 profile
codebook.build_from_watermarked('gemini_random')                   # adds 1536x2816 profile
codebook.save('codebook.npz')

# Later:
codebook.load('codebook.npz')
profile, res, exact = codebook.get_profile(1536, 2816)  # auto-select

SynthIDBypass โ€” three bypass generations:

bypass = SynthIDBypass()

result = bypass.bypass_simple(image, jpeg_quality=50)           # V1
result = bypass.bypass_v2(image, strength='aggressive')          # V2
result = bypass.bypass_v3(image, codebook, strength='aggressive') # V3 (best)

Multi-scale watermark detector (90% accuracy):

from robust_extractor import RobustSynthIDExtractor

extractor = RobustSynthIDExtractor()
extractor.load_codebook('artifacts/codebook/robust_codebook.pkl')
result = extractor.detect_array(image)
print(f"Watermarked: {result.is_watermarked}, Confidence: {result.confidence:.4f}")


๐Ÿ‘ค Maintainer & Contact

Alosh Denny AI Watermarking Research ยท Signal Processing

๐Ÿ“ง Email: aloshdenny@gmail.com ๐Ÿ”— GitHub: https://github.com/aloshdenny

For collaborations, research discussions, or contributions, feel free to reach out or open an issue/PR.


This project is for research and educational purposes only. SynthID is proprietary technology owned by Google DeepMind. These tools are intended for:

  • Academic research on watermarking robustness
  • Security analysis of AI-generated content identification
  • Understanding spread-spectrum encoding methods

Do not use these tools to misrepresent AI-generated content as human-created.