Discovering, detecting, and surgically removing Google's AI watermark through spectral analysis
Visit us on PitchHut
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:
- Discovered the watermark's resolution-dependent carrier frequency structure
- Built a detector that identifies SynthID watermarks with 90% accuracy
- 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
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
- 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"
- Place them in new folders:
gemini_black_nb_pro/(for black)gemini_white_nb_pro/(for white)
- 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.
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.
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.
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
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% |
| 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 |
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
- SpectralCodebook stores resolution-specific profiles (carrier positions, magnitudes, phases)
- Auto resolution selection picks the exact profile or the closest match
- Direct known-signal subtraction weighted by phase consistency and cross-validation confidence
- Multi-pass schedule catches residual watermark energy missed by previous passes
- Per-channel weighting (G=1.0, R=0.85, B=0.70) matches SynthID's embedding strength
| Metric | Value |
|---|---|
| PSNR | 43.5 dB |
| SSIM | 0.997 |
| Carrier energy drop | 75.8% |
| Phase coherence drop (top-5 carriers) | 91.4% |
| 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
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.npzOr 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]
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 aggressiveStrength levels: gentle (minimal, ~45 dB) > moderate > aggressive (recommended) > maximum
python src/extraction/robust_extractor.py detect image.png \
--codebook artifacts/codebook/robust_codebook.pklreverse-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
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 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 โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
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):
- Confidence = phase_consistency x cross_validation_agreement
- DC exclusion โ soft ramp suppresses low-frequency generation biases
- Per-bin subtraction = wm_magnitude x confidence x removal_fraction x channel_weight
- Safety cap โ subtraction never exceeds 90-95% of the image's energy at any bin
- 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}")
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.
