mirror of
https://github.com/wiltodelta/remove-ai-watermarks.git
synced 2026-08-31 09:40:38 +02:00
Split SynthID campaign docs by detector, classifiers, and removal
Keep Model 1 as a research AI-versus-camera result outside the library. Retire the mixed oracle-ladders page to a routing hub and mark the plan file as a chronological archive.
This commit is contained in:
@@ -39,7 +39,7 @@ Before a release, read [`docs/release-and-distribution.md`](docs/release-and-dis
|
||||
|
||||
[`docs/module-internals.md`](docs/module-internals.md) is the canonical per-module map, including design decisions, thresholds, calibration history, incident records, and regression guards. Read the relevant section before changing a subsystem.
|
||||
|
||||
Research and current constraints are routed through [`docs/index.md`](docs/index.md), especially [`docs/known-limitations.md`](docs/known-limitations.md), [`docs/supported-signals.md`](docs/supported-signals.md), [`docs/synthid.md`](docs/synthid.md), and [`docs/watermarking-landscape.md`](docs/watermarking-landscape.md).
|
||||
Research and current constraints are routed through [`docs/index.md`](docs/index.md), especially [`docs/known-limitations.md`](docs/known-limitations.md), [`docs/supported-signals.md`](docs/supported-signals.md), [`docs/synthid.md`](docs/synthid.md), and [`docs/watermarking-landscape.md`](docs/watermarking-landscape.md). SynthID campaign logs are split: [`docs/synthid-detector-research.md`](docs/synthid-detector-research.md), [`docs/synthid-classifiers.md`](docs/synthid-classifiers.md), [`docs/synthid-removal-research.md`](docs/synthid-removal-research.md). The mixed plan file is an archive.
|
||||
|
||||
## Data safety
|
||||
|
||||
|
||||
+6
-2
@@ -24,8 +24,7 @@ to run the tool. Use the maintainer references only when changing the code.
|
||||
| [Verification plan](verification-plan.md) | Verification methods, completed measurements, and remaining validation gaps. |
|
||||
| [Release and distribution](release-and-distribution.md) | PyPI, Homebrew, Hugging Face Space, and release workflow. |
|
||||
| [Watermarking landscape](watermarking-landscape.md) | Vendor signals and detection approaches. |
|
||||
| [SynthID technical reference](synthid.md) | Mechanism, detector access, robustness, and implications for this project. |
|
||||
| [SynthID detector and removal plan](synthid-detector-removal-plan.md) | Gated research program for provider-specific local detection and pixel-only removal. |
|
||||
| [SynthID technical reference](synthid.md) | Mechanism, shipped lattice and provenance, robustness, regeneration. |
|
||||
|
||||
## Research archive
|
||||
|
||||
@@ -36,7 +35,12 @@ The current behavior is defined by the code, tests, README, and user guides.
|
||||
- [ControlNet removal research](controlnet-removal-pipeline-research.md)
|
||||
- [Qwen improvement research](qwen-improvement-research.md)
|
||||
- [Doubao reverse-alpha research](research-doubao-distillation.md)
|
||||
- [SynthID local detector research](synthid-detector-research.md)
|
||||
- [Classifier models](synthid-classifiers.md) (Model 1 result)
|
||||
- [SynthID mark removal research](synthid-removal-research.md)
|
||||
- [SynthID identity research](synthid-robust-identity-research.md)
|
||||
- [SynthID identity follow-up](synthid-robust-identity-research-2026-06-08.md)
|
||||
- [Video SynthID quality research](video-synthid-quality-research.md)
|
||||
- [OpenAI SynthID oracle ladders](synthid-oracle-ladders.md) (routing hub)
|
||||
- [SynthID detector and removal plan](synthid-detector-removal-plan.md) (chronological mixed archive)
|
||||
- [Text protection research](text-protection-research.md)
|
||||
|
||||
@@ -64,6 +64,14 @@ identity or exact texture, and each then runs the same face stage.
|
||||
`qwen-zimage` is the higher fidelity of the two. Both are large, slow, and may
|
||||
still alter small text or difficult faces.
|
||||
|
||||
Camera-pipeline tricks and mild geometry do not replace regeneration for
|
||||
OpenAI SynthID. On 2026-08-22 the official verifier still returned
|
||||
`detected` after Bayer mosaic plus bilinear or VNG demosaic, an upscale-
|
||||
then-Bayer round trip, barrel distortion, and scanline jitter. 16-32 px
|
||||
phase scramble still flipped the same seeds at similar or better PSNR.
|
||||
Those attacks are closed as quiet removers. Numbers:
|
||||
[synthid-removal-research.md](synthid-removal-research.md).
|
||||
|
||||
### The experimental pixel route reads a pipeline lattice, not the watermark
|
||||
|
||||
Signed provenance is the primary and supported route for SynthID in this
|
||||
@@ -94,8 +102,12 @@ The published control rates for this route were all measured on photographs.
|
||||
Against other generators' output, which is the population a provenance tool is
|
||||
actually pointed at, the shipped runtime accepted 29 of 223 signed non-Google
|
||||
images on 2026-08-16: 13.0% overall, 24.1% on Adobe Firefly, with a top score
|
||||
of 3.01 against a threshold of 1.0. Treat a positive as evidence only when the
|
||||
alternative generators have been ruled out by other means.
|
||||
of 3.01 against a threshold of 1.0. A 2026-08-22 re-check of the same
|
||||
production entry point on frozen holdouts found Firefly 15/84 and PixelBin
|
||||
11/80, with photographs at 0/24 Kodak and 0/60 Open Images, and a two-pixel
|
||||
crop removing every sampled positive. Treat a positive as evidence of the
|
||||
Google-lineage renderer family, not Gemini and not a watermark, and only
|
||||
when the alternative generators have been ruled out by other means.
|
||||
|
||||
Sensitivity has only ever been reported on images the route was calibrated
|
||||
against. The first out-of-distribution measurement was taken on 2026-08-16: 11
|
||||
|
||||
@@ -645,7 +645,11 @@ whose C2PA names a non-Google generator, the unchanged entry point accepted 29
|
||||
(`0.130`, Adobe Firefly `0.241`, highest foreign score `3.01`), all from
|
||||
registered-v3. The branch reads a lattice shared across generation pipelines,
|
||||
which is why `identify` reports it as the experimental `pipeline_lattice`
|
||||
signal and never as a watermark.
|
||||
signal and never as a watermark. A 2026-08-22 production re-check on 628
|
||||
frozen holdouts repeated that family pattern (Google 45/80, Firefly 15/84,
|
||||
PixelBin 11/80, OpenAI 1/80, Kodak 0/24) and a two-pixel crop again removed
|
||||
every sampled positive. Classifier context:
|
||||
[synthid-classifiers.md](synthid-classifiers.md).
|
||||
|
||||
The branch is also phase-locked to the image origin, exactly like the large
|
||||
expert. A two-pixel diagonal crop killed all 28 in-geometry foreign detections
|
||||
|
||||
@@ -139,7 +139,9 @@ Google images), while the published SynthID evaluation survives aggressive crop
|
||||
and resize, so every control rate below describes a generation-pipeline
|
||||
signature and not watermark detection. Every rate quoted
|
||||
below was also measured on photographs; on 223 signed non-Google generator
|
||||
images the same runtime accepted 29, a rate of 13.0%. Sensitivity outside the
|
||||
images the same runtime accepted 29, a rate of 13.0%. A 2026-08-22 re-check
|
||||
on frozen holdouts was Firefly 15/84, PixelBin 11/80, OpenAI 1/80, Kodak
|
||||
0/24. Sensitivity outside the
|
||||
calibration distribution was measured once, on 11 fresh 5632x3072 images from
|
||||
`gemini-3.1-flash-image`: 8 detected, 72.7%, one-sided 95% lower bound 43.6%.
|
||||
The same images cropped seven pixels off the tile grid returned 0 of 6.
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
# Classifier models (research)
|
||||
|
||||
> Research archive for pixel classifiers that are *not* SynthID detectors.
|
||||
> Not a statement of current product capability. Shipped behavior:
|
||||
> [supported signals](supported-signals.md) and
|
||||
> [known limitations](known-limitations.md).
|
||||
>
|
||||
> Sister pages: [SynthID local detector](synthid-detector-research.md),
|
||||
> [SynthID mark removal](synthid-removal-research.md),
|
||||
> [mechanism reference](synthid.md).
|
||||
|
||||
A classifier is reliable only when its name matches its errors, photographs
|
||||
are the first negative, Firefly and PixelBin are in the test, and a watermark
|
||||
claim uses an independent oracle. CLIP content embeddings and the 124-d
|
||||
origin-locked residual bank are different features for different jobs.
|
||||
|
||||
## Result: Model 1, AI versus camera
|
||||
|
||||
Finetuned CLIP-L (`openai/clip-vit-large-patch14`), last two vision blocks,
|
||||
224 letterbox, JPEG and mild crop, linear ridge. Train 5,221 AI plus 6,129
|
||||
photos. Locked Open Images fresh never enters train. Operating point: 1%
|
||||
FPR on disjoint `photo_dev_oi`.
|
||||
|
||||
| Cell | Value |
|
||||
| --- | --- |
|
||||
| Kodak | 0/24 |
|
||||
| Open Images fresh FPR | 1.7% (n=3,000) |
|
||||
| Exact-1024 Open Images FPR | 6% |
|
||||
| AI-test TPR | 93.0% (n=1,905) |
|
||||
| OpenAI | 93.2% |
|
||||
| Gemini | 90.5% |
|
||||
| Firefly | 94.0% |
|
||||
| xAI | 96.1% |
|
||||
| FLUX hold | 92.7% |
|
||||
|
||||
51 fresh false positives are mostly graphics, CGI, product cutouts, and
|
||||
scans, not Gemini. Nobody in the sweep hit both ≤1% fresh FPR and ≥90%
|
||||
TPR. This is AI-versus-camera, not SynthID, and it is not in `identify`.
|
||||
|
||||
Artifacts: `.local-eval/synthid/ai-photo-2026-08-22/`
|
||||
(`comparison.json`, `probe-report-clip-l-ft.json`,
|
||||
`probe-weights-clip-l-ft.npz`). Date cutoff 2026-07-23, seed 20260822.
|
||||
|
||||
### Rejected Model 1 variants
|
||||
|
||||
Same splits and `photo_dev_oi` 1% cut.
|
||||
|
||||
| Variant | Fresh FPR | Kodak | 1024 FPR | AI TPR | FLUX hold |
|
||||
| --- | ---: | ---: | ---: | ---: | ---: |
|
||||
| CLIP-L v2 | 0.017 | 0/24 | 0.04 | 0.877 | n/a |
|
||||
| CLIP-L + FLUX extra | 0.016 | 0/24 | 0.05 | 0.861 | 0.707 |
|
||||
| CLIP-H + FLUX extra | 0.014 | 0/24 | 0.02 | 0.812 | 0.913 |
|
||||
| CLIP-L last-2-blocks finetune | 0.017 | 0/24 | 0.06 | **0.930** | **0.927** |
|
||||
| DINOv2-giant 256 | 0.023 | 0/24 | 0.04 | 0.606 | 0.293 |
|
||||
|
||||
CLIP-H is the photo-FPR specialist (1.4% fresh, 2% at 1024) at 81% TPR and
|
||||
is not the result. DINOv2-giant at 256 px is not usable.
|
||||
|
||||
v1 (CLIP-L, no Open Images in train) at a COCO-looking 0.5% cut accepted
|
||||
13% of Open Images. Domain shift, not the 124 residual bank. v2 added
|
||||
1,000 disjoint Open Images reserve photos to train and 500 as
|
||||
`photo_dev_oi`; locked fresh stayed 1.7% FPR at 87.7% TPR before
|
||||
finetune.
|
||||
|
||||
The 124-d residual bank is the wrong feature for "AI or not". At a
|
||||
Kodak-safe cut it catches 60% Firefly and misses FLUX, NovelAI, Reve, and
|
||||
most of TC260 and xAI. Do not train another ridge on that representation
|
||||
for an AI-or-not claim.
|
||||
|
||||
Open, if this head is ever considered for a product cut: a graphics/CGI
|
||||
abstain. CLIP treats non-camera imagery as generation; that is the remaining
|
||||
error, not Gemini contamination.
|
||||
|
||||
## Closed: provider names from pixels
|
||||
|
||||
Three-way `openai` / `google` / `other` on Model 1 embeddings fails the
|
||||
Firefly gate. CLIP-L-ft test accuracy 0.53; Firefly 35/31/18. CLIP-H 0.57;
|
||||
Firefly 36/33/15. OpenAI versus Gemini AUC on CLIP-L-ft is 0.845; on the
|
||||
124-d lattice bank it is 0.989. They are two pipelines, not one class.
|
||||
|
||||
Collapsing OpenAI and Gemini into one pixel class versus other generators
|
||||
does not fix that. Binary ridge AUC 0.686, TPR 75% at FPR 45%. Canva 98%,
|
||||
Microsoft 75%, Firefly 68% leak into the union; FLUX HF hold stays out at
|
||||
3%. Training the same union only against photographs recreates Model 1 with
|
||||
a narrower train set (fresh FPR 2.1%, Firefly still 95%).
|
||||
|
||||
`provider-report-clip-l-ft.json`, `provider-union-report.json`.
|
||||
|
||||
### 124-d lattice as pipeline ID, not a vendor CLIP head
|
||||
|
||||
Provider-class ridge on 124 native residual features (70/30 once, not a
|
||||
watermark gate). OpenAI L1 n=285, Google corpus n=533, foreign n=218, COCO
|
||||
n=289: OpenAI vs COCO 0.965; Google vs COCO 0.999; OpenAI vs Google 0.989;
|
||||
OpenAI vs foreign 0.725; Google vs foreign 0.922. OpenAI vs Firefly-class
|
||||
is the weak cell.
|
||||
|
||||
One-vs-rest: Google head at TPR 90% has FPR 0% vs COCO, 14% vs foreign, 2%
|
||||
vs OpenAI. A Gemini-like pixel class is close to what `pipeline_lattice`
|
||||
already is. An OpenAI-like pixel class on this bank would label Firefly as
|
||||
OpenAI about half the time and is not shippable.
|
||||
|
||||
Three-class `openai` / `google` / `no_ai` on 2,000 catalog OpenAI, 2,000
|
||||
catalog Google, and 1,936 COCO photos. Photo-first margin 0.50: openai
|
||||
74.7%, google 78.9%, no_ai 99.8%; Kodak 24/24 `no_ai`. Other generators
|
||||
are leakage, not classes:
|
||||
|
||||
| Platform | n | openai | google | no_ai |
|
||||
| --- | ---: | ---: | ---: | ---: |
|
||||
| Firefly | 106 | 37 | 27 | 42 |
|
||||
| Microsoft | 117 | 39 | 22 | 56 |
|
||||
| PixelBin | 90 | 14 | 46 | 30 |
|
||||
| HuggingFace job | 82 | 3 | 62 | 17 |
|
||||
| ByteDance C2PA | 86 | 5 | 35 | 46 |
|
||||
| SD / Comfy | 120 | 30 | 11 | 79 |
|
||||
| fal.ai | 98 | 11 | 18 | 69 |
|
||||
| Made-with-AI tag | 115 | 4 | 32 | 79 |
|
||||
| TC260 | 118 | 1 | 13 | 104 |
|
||||
| xAI | 114 | 1 | 20 | 93 |
|
||||
| Canva | 76 | 11 | 3 | 62 |
|
||||
| Apple Clean Up | 114 | 1 | 23 | 90 |
|
||||
| Aweme | 37 | 2 | 7 | 28 |
|
||||
| FLUX | 11 | 0 | 0 | 11 |
|
||||
| Reve | 10 | 0 | 0 | 10 |
|
||||
| NovelAI | 9 | 0 | 0 | 9 |
|
||||
| Higgsfield | 11 | 1 | 5 | 5 |
|
||||
|
||||
PixelBin and HuggingFace jobs lean `google` (shared renderer lineage).
|
||||
FLUX, NovelAI, and Reve stay `no_ai`. Local probe:
|
||||
`uv run python .local-eval/synthid/prc-oklab-attack-2026-08-15/classify_openai_gemini.py image.png`.
|
||||
|
||||
## Production `pipeline_lattice` (google-lineage renderer)
|
||||
|
||||
Experimental signal in `identify`, never a watermark. Production
|
||||
`detect_synthid` re-check on 628 frozen holdouts, seed 20260822, threshold
|
||||
1.0.
|
||||
|
||||
| Family | n | detected | rate | max score |
|
||||
| --- | ---: | ---: | ---: | ---: |
|
||||
| Google / Gemini | 80 | 45 | 0.56 | 3.03 |
|
||||
| Firefly | 84 | 15 | 0.18 | 3.00 |
|
||||
| PixelBin | 80 | 11 | 0.14 | 2.48 |
|
||||
| Microsoft | 60 | 2 | 0.03 | 2.40 |
|
||||
| OpenAI | 80 | 1 | 0.01 | 1.38 |
|
||||
| xAI | 40 | 1 | 0.03 | 1.26 |
|
||||
| FLUX HF | 40 | 0 | 0 | 0.85 |
|
||||
| TC260 | 40 | 0 | 0 | 0.97 |
|
||||
| Kodak | 24 | 0 | 0 | 0.49 |
|
||||
| Open Images fresh | 60 | 0 | 0 | 0.64 |
|
||||
| COCO hold | 40 | 0 | 0 | 0.74 |
|
||||
|
||||
Firefly 18% and PixelBin 14% match the 2026-08-16 signed-foreign rates
|
||||
(24% and 14%) in order of magnitude. Both Microsoft hits have issuer
|
||||
`Microsoft, Google LLC`. A 2 px crop killed every sampled positive,
|
||||
including Firefly and PixelBin. Google TPR 56% is mixed Spaces eras, not
|
||||
the oracle-positive 147/148 cell. Honest name:
|
||||
`google_lineage_renderer` = Gemini/Imagen + Firefly + PixelBin.
|
||||
|
||||
Registered-v3 photographic controls remain 0/5,993 Open Images and 0/2,366
|
||||
COCO. Against 223 C2PA-named non-Google generators on 2026-08-16: 29
|
||||
accepted (0.130), Firefly 0.241. `.local-eval/synthid/lattice-check-2026-08-22/`.
|
||||
|
||||
## Spaces catalog sizes (2026-08-21)
|
||||
|
||||
49,082 unique sha256. Unlabeled 24,832 rows are not photographs. Microsoft
|
||||
127/279 and Firefly 64/210 also carry `synthid_from_provenance=true`, so
|
||||
that flag is not an OpenAI-plus-Gemini class.
|
||||
|
||||
| Platform | n |
|
||||
| --- | ---: |
|
||||
| none / unlabeled | 24,832 |
|
||||
| OpenAI | 11,722 (11,347 SynthID-from-provenance) |
|
||||
| Google / Gemini | 6,875 (plus 94 Google C2PA without a named generator) |
|
||||
| China AIGC TC260 (not a brand) | 3,610 |
|
||||
| Microsoft | 279 |
|
||||
| Meta-style Made-with-AI tag | 275 |
|
||||
| Adobe Firefly | 210 |
|
||||
| xAI | 179 |
|
||||
| local SD / Comfy | 178 |
|
||||
| ByteDance platform | 88 |
|
||||
| fal.ai | 98 |
|
||||
| Canva | 79 |
|
||||
| ByteDance Aweme tag | 40 |
|
||||
| Dreamina tag | 4 |
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,123 @@
|
||||
# SynthID local detector research
|
||||
|
||||
> Research archive for the hunt for a local, keyless SynthID pixel detector.
|
||||
> Not a statement of current product capability. Shipped behavior:
|
||||
> [supported signals](supported-signals.md) and
|
||||
> [known limitations](known-limitations.md).
|
||||
>
|
||||
> Sister pages: [classifier models](synthid-classifiers.md),
|
||||
> [SynthID mark removal](synthid-removal-research.md),
|
||||
> [mechanism reference](synthid.md). Dated measurements live in the
|
||||
> [chronological plan](synthid-detector-removal-plan.md).
|
||||
|
||||
## Result
|
||||
|
||||
The local OpenAI SynthID detector hunt closed 2026-08-20. Google has no
|
||||
public payload decoder. Nothing in this project reproduces one.
|
||||
|
||||
The mark behaves like a keyed spread-spectrum residual: a content-adaptive
|
||||
`x' = x + g(x)` with a paired decoder (DeepMind patent family, optional
|
||||
secret in intermediate layers, encoder/decoder ensembles that do not
|
||||
recognize each other). Without that pair, the residual sits under the
|
||||
scene. Keyless energy, TrustMark transfer, L1 distillation, a flat-field
|
||||
stamp, and a 16-32 band student all failed to read the official oracle
|
||||
contrast on photographs.
|
||||
|
||||
What the product uses for the *watermark* is signed provenance and
|
||||
`verify-openai-synthid`. The experimental pixel route in `identify` is
|
||||
`pipeline_lattice`, a generation-pipeline ID, not SynthID. Lineage rates
|
||||
for that route are in [classifier models](synthid-classifiers.md).
|
||||
|
||||
## Closed detector routes
|
||||
|
||||
| Route | Close | Why |
|
||||
| --- | --- | --- |
|
||||
| Keyless energy in 16-32 px | 2026-08-20 | L1 AUC 0.53; official decoder reads phase structure, not energy |
|
||||
| TrustMark / open-encoder transfer | 2026-08-20 | E3 leave-one-encoder-out at chance on TrustMark (0.505 ridge, 0.510 conv) |
|
||||
| L1 distillation of oracle bits | 2026-08-20 | Geometry-only AUC 0.78-0.83 beats pixel 124-d (0.64). ChatGPT export and `opened` C2PA predict `not_detected`. Inside 1254x1254, permutation p=0.45 |
|
||||
| Flat 16-32 matched filter | 2026-08-21 | Leave-one-out residual correlation 0.645 on gray flats; 0.007-0.025 on COCO photo residuals. L1 AUC 0.70 was a size confound (size-matched 0.59 / 0.44) |
|
||||
| `gpt-image-1` as encoder-off pair | 2026-08-21 | Does not stamp. `gpt-image-2` does |
|
||||
| CNN on raw L1 bits | 2026-08-21 | Do not train. Labels are export geometry and presentation, not the mark |
|
||||
| Origin-locked lattice as SynthID | 2026-08-16 | Two-pixel crop kills it; published SynthID keeps 99.97% TPR under aggressive crop. See classifiers for the honest `google_lineage_renderer` name |
|
||||
|
||||
Open: Google (no oracle); `chatgpt-image-latest` once the organization is
|
||||
verified. A size-specific whitened 16-32 template on photographs is not
|
||||
justified until amplitude is measured without the flat-arm G.
|
||||
|
||||
## Oracle and seeds
|
||||
|
||||
Official `POST /v1/content_provenance_checks`, metadata stripped, pixels
|
||||
preserved. Raw files stay gitignored under
|
||||
`.local-eval/synthid/prc-oklab-attack-2026-08-15/`.
|
||||
|
||||
| Seed | Path | Size |
|
||||
| --- | --- | --- |
|
||||
| s1 | `originals/2026-05-31/31e55ea8a4de42029659654a80814630_src.png` | 1024x1536 |
|
||||
| s2 | `originals/2026-05-31/37ae95821a3447c78f94e56bdebf0c88_src.png` | 1024x1536 |
|
||||
| s3 | `originals/2026-07-10/d76f35fee69e4531865e88b786fa52e5_src.png` | 1086x1448 |
|
||||
|
||||
All three `detected` before attacks.
|
||||
|
||||
## Source-matched pairs (2026-08-21)
|
||||
|
||||
`gpt-image-2` (ChatGPT Images 2.0) can mint encoder-on/off pairs.
|
||||
`chatgpt-image-latest` is 403 until the org is verified.
|
||||
|
||||
| Input | C2PA | Oracle | Aligned PSNR |
|
||||
| --- | --- | --- | ---: |
|
||||
| Camera JPEG 960x1280 | none | not_detected | - |
|
||||
| ChatGPT UI + frame 1086x1448 | watermarked.unbound | detected | 16.6 dB (redraw) |
|
||||
| `gpt-image-1` edit, high fidelity, red dot | created, converted only | not_detected | 30.9 dB |
|
||||
| `gpt-image-2` edit, red dot 1024x1536 | watermarked.unbound | detected | 28.2 dB |
|
||||
|
||||
The `gpt-image-2` photo residual is broadband (std 9.1), not a 16-32 stamp.
|
||||
COCO `gpt-image-2` edits: 11/12 `watermarked.unbound`, one safety block.
|
||||
|
||||
Solid gray/white through `gpt-image-2` "reproduce exactly" is
|
||||
`watermarked.unbound`. Gray 128 at 1024x1536: PSNR 41.9 dB vs the flat,
|
||||
source `not_detected`, output `detected`. Other gray levels 32-220: PSNR
|
||||
38-49 dB. Eight gray 1024x1536 residuals, leave-one-out correlation after
|
||||
highpass: 0.645 (shuffle 0). That shared stamp does not transfer to COCO
|
||||
photo residuals (0.007-0.025).
|
||||
|
||||
## Presentation gate versus residual
|
||||
|
||||
An official `not_detected` is not one event. Collage, photo-pad, two-panel
|
||||
self-concat, and 8x8 scramble can be a *presentation gate* (this upload is
|
||||
not a single photograph). Blur sigma 7 and in-band 16-32 destruction sit on
|
||||
the single-photo manifold and are residual damage; those belong in
|
||||
[mark removal](synthid-removal-research.md).
|
||||
|
||||
Do not train a surrogate on mixed collage misses if the goal is a mark
|
||||
student.
|
||||
|
||||
Identity (s1, 2026-08-19): JPEG q80/q20, crop 2 px, crop 8 px, keep 0.75
|
||||
and 0.50, rot90, rotate 5, flip, grayscale all stay `detected`.
|
||||
|
||||
Token / layout (s1): each quadrant at 512x768 `detected`; `hstack` and
|
||||
`vstack` of marked\|marked `not_detected`; 4x4 tile scramble `detected`;
|
||||
8x8 `not_detected`. Two copies of a detecting image still miss. Tomography
|
||||
3x3: all nine cells `not_detected` (a 1/9 window is below support).
|
||||
|
||||
Preprocess E1 (s1): stretch 2x `detected`; centre-crop of marked\|marked
|
||||
hstack back to native `detected`; 0.20x pixels on a native-size white
|
||||
canvas `not_detected` (the same 0.20x file uploaded alone was `detected`).
|
||||
|
||||
## L1 is not a mark task
|
||||
|
||||
Control-only 283 rows: 203 detected, 80 not_detected. Forward-temporal
|
||||
nested ridge on 124 pixel features: AUC 0.649 / 0.641. Geometry-only:
|
||||
0.781 / 0.826. All 21 `claim_generator=ChatGPT` controls are
|
||||
`not_detected`. C2PA `opened`: 24/24 `not_detected`. Inside 1254x1254,
|
||||
mean-feature permutation p=0.45.
|
||||
|
||||
OpenAI-supervised ridge on 16-32 band-passed `image_features`:
|
||||
forward-temporal AUC 0.53 vs L1 `not_detected`, 0.95 vs COCO, 0.97 vs COCO
|
||||
after a 2 px crop. The student learns OpenAI-versus-photo and still does
|
||||
not see the oracle mark contrast.
|
||||
|
||||
## Product remainder for the watermark
|
||||
|
||||
Signed provenance (`identify`) and `verify-openai-synthid` (remote, explicit
|
||||
upload). A local `indeterminate` from `detect-synthid` is not a clean
|
||||
SynthID negative.
|
||||
@@ -0,0 +1,30 @@
|
||||
# OpenAI SynthID oracle ladders
|
||||
|
||||
> This page is a routing hub. The mixed 2026-08 campaign log was split by
|
||||
> purpose on 2026-08-22. Numeric tables now live on the page for that
|
||||
> purpose. Raw images stay gitignored under
|
||||
> `.local-eval/synthid/prc-oklab-attack-2026-08-15/`.
|
||||
>
|
||||
> Seeds s1, s2, s3 are listed in
|
||||
> [SynthID local detector research](synthid-detector-research.md).
|
||||
|
||||
| Page | Use it for |
|
||||
| --- | --- |
|
||||
| [SynthID local detector research](synthid-detector-research.md) | Hunt for a keyless local mark detector. Closed. |
|
||||
| [Classifier models](synthid-classifiers.md) | Model 1 AI-versus-camera result, rejected provider CLIP, `pipeline_lattice` as google-lineage. |
|
||||
| [SynthID mark removal research](synthid-removal-research.md) | Quiet-remover hunt. Closed except ~19-24 dB 16-32 scramble and blur sigma 7. |
|
||||
| [Mechanism reference](synthid.md) | How SynthID works, provenance, shipped lattice, regeneration. |
|
||||
| [Chronological plan archive](synthid-detector-removal-plan.md) | Dated H-gates, corpora, and session notes in original order. |
|
||||
|
||||
## Where former sections went
|
||||
|
||||
| Former heading | Now |
|
||||
| --- | --- |
|
||||
| 2026-08-21 pairs, flats, L1 labels | [detector](synthid-detector-research.md) |
|
||||
| Identity, token/layout, tomography, preprocess E1 | [detector](synthid-detector-research.md) (presentation gate) |
|
||||
| L1 repair, L1 geometry, camera vs edit pair, E3 | [detector](synthid-detector-research.md) |
|
||||
| CLIP-L photo vs AI, provider CLIP, union | [classifiers](synthid-classifiers.md) |
|
||||
| 124-d three-class and binary AI | [classifiers](synthid-classifiers.md) |
|
||||
| `pipeline_lattice` re-check, Spaces census | [classifiers](synthid-classifiers.md) |
|
||||
| Attack / kill / flip / add / surround ladders | [removal](synthid-removal-research.md) |
|
||||
| 16-32 titration, E2 scramble, Bayer and geometry | [removal](synthid-removal-research.md) |
|
||||
@@ -0,0 +1,141 @@
|
||||
# SynthID mark removal research
|
||||
|
||||
> Research archive for pixel-only SynthID removal, not diffusion
|
||||
> regeneration. Not a statement of current product capability. Shipped
|
||||
> invisible removal is lossy regeneration:
|
||||
> [known limitations](known-limitations.md).
|
||||
>
|
||||
> Sister pages: [SynthID local detector](synthid-detector-research.md),
|
||||
> [classifier models](synthid-classifiers.md),
|
||||
> [mechanism reference](synthid.md).
|
||||
|
||||
## Result
|
||||
|
||||
The quality-preserving OpenAI SynthID remover hunt closed 2026-08-20.
|
||||
Bayer, VNG demosaic, upscale-then-Bayer, barrel distortion, and scanline
|
||||
jitter closed 2026-08-22: they leave the official oracle `detected`.
|
||||
|
||||
Working residual kills on photographs cost about 19-24 dB:
|
||||
|
||||
- 16-32 px phase scramble (s1 24.6 dB, fish 24.3 dB, s2 19.0 dB)
|
||||
- Gaussian blur sigma 7 (23.8 dB), holds 3/3 versus sigma 6
|
||||
- Additive 16-32 jam only at a=24 / 18.6 dB, worse than scramble
|
||||
|
||||
JPEG q5, noise sigma 16, grayscale, rot90, flip, 5°, downscale 0.20x,
|
||||
median 7, posterize 4, VAE round-trip, and white pad to 40% linear stay
|
||||
`detected`. Elastic warp is not a stable kill (s3 still `detected` at
|
||||
22.0 dB).
|
||||
|
||||
The product remainder is diffusion regeneration (`qwen-zimage` /
|
||||
`sdxl-zimage`), which does not decode and delete a payload. Defeating the
|
||||
verifier does not restore forensic deniability; see
|
||||
[synthid.md](synthid.md#23-removal-attacks-and-forensic-detectability).
|
||||
|
||||
Official `not_detected` on collage, photo-pad, and two-panel layouts is a
|
||||
presentation gate, not residual damage. Those rungs are in
|
||||
[detector research](synthid-detector-research.md).
|
||||
|
||||
## Closed quiet removers
|
||||
|
||||
| Attack | Close | Notes |
|
||||
| --- | --- | --- |
|
||||
| Quality-preserving photo remover | 2026-08-20 | Every residual `not_detected` that is not a collage is below usable quality |
|
||||
| Additive in-band jam as a quiet remover | 2026-08-21 | Fish flips only at 18.6 dB; 4-8 px at the same PSNR stays `detected` |
|
||||
| Bayer bilinear / VNG / upscale-Bayer | 2026-08-22 | s1/s2 still `detected`; VNG on s2 is dirtier than scramble (18.5 vs 19.0 dB) and the mark remains |
|
||||
| Barrel k1=0.06 and scanline ±0.8 px | 2026-08-22 | s1/s2 `detected` even at 14-20 dB barrel |
|
||||
| TrustMark-style micro-warp | 2026-08-21 | 0.25 px / 32 dB still 100% detect on TrustMark P; OpenAI elastic ~21 dB unreplicated |
|
||||
|
||||
Oracle: `verify_openai_synthid` after AI-metadata strip. Seeds s1, s2, s3
|
||||
as in [detector research](synthid-detector-research.md). Raw files:
|
||||
`.local-eval/synthid/prc-oklab-attack-2026-08-15/`.
|
||||
|
||||
## Band that actually carries the mark
|
||||
|
||||
Phase-randomize one octave at a time, preserve energy (E2, s1, replicated
|
||||
p16_32 on s2 and s3):
|
||||
|
||||
| Octave (period px) | Verdict |
|
||||
| --- | --- |
|
||||
| 2-4 | detected |
|
||||
| 4-8 | detected |
|
||||
| 8-16 | detected |
|
||||
| 16-32 | not_detected |
|
||||
| 32-64 | detected |
|
||||
| 64-128 | detected |
|
||||
|
||||
Destroying only 16-32 px periods silences the official decoder. The
|
||||
lattice band 8-16 px does not. On a marked gray flat the same scramble is
|
||||
51.1 dB `not_detected` because the band is almost empty. On a photograph
|
||||
the band holds the scene (24.3 dB). Replacing native 16-32 with a
|
||||
2x-pyramid prediction is 48.4 dB and still `detected`.
|
||||
|
||||
Fish additive jam, luma RMS `a`:
|
||||
|
||||
| Band | a | PSNR | Verdict |
|
||||
| --- | ---: | ---: | --- |
|
||||
| 16-32 | 0.06-4.0 | 51.2-33.6 | detected |
|
||||
| 16-32 | 8 | 27.7 | detected |
|
||||
| 16-32 | 16 | 21.9 | detected |
|
||||
| 16-32 | 24 | 18.6 | not_detected |
|
||||
| 4-8 | 16 | 21.9 | detected |
|
||||
| 4-8 | 24 | 18.6 | detected |
|
||||
|
||||
Preregistered close `a*_photo < 0.53` failed (`a* > 16`).
|
||||
|
||||
## Bayer and geometry (2026-08-22)
|
||||
|
||||
Frozen one-pass batch. Lattice scores on these OpenAI sources are already
|
||||
`indeterminate` and are not the label. s3 and the fish photo were queued
|
||||
after an OpenAI 429.
|
||||
|
||||
| Attack | s1 PSNR / oracle | s2 PSNR / oracle |
|
||||
| --- | --- | --- |
|
||||
| source | detected | detected |
|
||||
| Bayer bilinear | 32.7 detected | 28.4 detected |
|
||||
| Bayer VNG | 25.0 detected | 18.5 detected |
|
||||
| upscale 1.15 then Bayer | 33.9 detected | 29.8 detected |
|
||||
| barrel k1=0.06 | 19.9 detected | 14.2 detected |
|
||||
| scanline ±0.8 px | 31.5 detected | 26.7 detected |
|
||||
| shift 2 px | 23.1 detected | (429, not submitted) |
|
||||
| 16-32 phase scramble | 24.6 not_detected | 19.0 not_detected |
|
||||
|
||||
Camera pipeline and mild geometry do not hit the decoder basis. A 2 px
|
||||
shift, which kills `pipeline_lattice`, left s1 `detected`.
|
||||
`.local-eval/synthid/prc-oklab-attack-2026-08-15/bayer-geometry-2026-08-22/`.
|
||||
|
||||
## Attack ladders (OpenAI oracle)
|
||||
|
||||
Pilot 2026-08-17 (n=3): JPEG q40, 0.5x, noise8+jpeg85, 0.35x+jpeg50 all
|
||||
`detected` (s2 0.35x+jpeg50 at 20.1 dB still detected).
|
||||
|
||||
Kill and flip (s1), then replication 3/3:
|
||||
|
||||
| Rung | s1 | s2 | s3 |
|
||||
| --- | --- | --- | --- |
|
||||
| blur sigma 6 | detected | detected | detected |
|
||||
| blur sigma 7 | not_detected | not_detected | not_detected |
|
||||
| keep 0.50 linear | detected | detected | detected |
|
||||
| keep 0.40 linear | not_detected | not_detected | not_detected |
|
||||
| elastic ~24 dB | detected 24.6 | detected 17.9 | detected 26.1 |
|
||||
| elastic ~21 dB | not_detected 20.8 | not_detected 14.8 | detected 22.0 |
|
||||
| pad white 40% linear | detected | detected | detected |
|
||||
| hstack with photo | not_detected | not_detected | not_detected |
|
||||
| blend 25% marked | detected | detected | detected |
|
||||
| inset native 1:1 on 2x photo | not_detected | not_detected | not_detected |
|
||||
| JPEG q5 | detected | detected | detected |
|
||||
|
||||
Holds on 3/3: blur 6 vs 7, crop keep 0.50 vs 0.40, white pad 40%
|
||||
`detected`, hstack `not_detected`, blend 25% `detected`, JPEG q5
|
||||
`detected`. Elastic at ~21 dB does not hold. Crop keep-0.40 and hstack
|
||||
are presentation or support, not a quiet residual wipe.
|
||||
|
||||
Surround: photo fill at the white-pad geometries is `not_detected` on
|
||||
3/3; white pad at those sizes was `detected`. Unmarked photo strip flips
|
||||
between 25% width (`detected`) and 35% (`not_detected`). Photo frame 15%
|
||||
each side is `not_detected` on 3/3; 12% does not hold.
|
||||
|
||||
## Product remainder for removal
|
||||
|
||||
Invisible removal in this package regenerates through `qwen-zimage` or
|
||||
`sdxl-zimage`. It is lossy. There is no shipped pixel-only OpenAI or
|
||||
Google SynthID wipe. Do not add Bayer or geometry as remover arms.
|
||||
+24
-4
@@ -1,8 +1,12 @@
|
||||
# SynthID: technical reference
|
||||
|
||||
> Technical research reference. Current package behavior is defined by the
|
||||
> Technical research reference for the mark itself and for what this package
|
||||
> ships. Current package behavior is defined by the
|
||||
> [supported signals](supported-signals.md), [known limitations](known-limitations.md),
|
||||
> and [module internals](module-internals.md). Dated measurements below are
|
||||
> and [module internals](module-internals.md). Campaign results are split:
|
||||
> [local detector](synthid-detector-research.md),
|
||||
> [classifier models](synthid-classifiers.md),
|
||||
> [mark removal](synthid-removal-research.md). Dated measurements below are
|
||||
> historical evidence and should not be read as current CLI defaults.
|
||||
|
||||
This document covers how Google SynthID for images works mechanically, what it
|
||||
@@ -224,8 +228,20 @@ conversion (the body text of Section 10 is absent from the HTML).
|
||||
**What is known empirically from our own oracle-verified testing.**
|
||||
|
||||
A 2026-08-09 non-generative pilot found a promising Google phase-correlate,
|
||||
but did not establish a releasable local detector or pixel-only remover. The
|
||||
best independently fitted model relearned phase and magnitude from four of our
|
||||
but did not establish a releasable local detector or pixel-only remover.
|
||||
The 2026-08-20/22 OpenAI campaign is split by purpose:
|
||||
[local detector](synthid-detector-research.md) (closed),
|
||||
[classifier models](synthid-classifiers.md) (Model 1 CLIP-L is the
|
||||
AI-versus-camera result), and
|
||||
[mark removal](synthid-removal-research.md) (quiet remover closed; 16-32
|
||||
phase scramble and blur sigma 7 still kill). JPEG q5 and 16-32 px phase
|
||||
structure survive as the official mark. `gpt-image-2` source-matched flat
|
||||
pairs exist; their residual does not transfer to photographs. Bayer and
|
||||
mild geometry do not flip the oracle. Model 1 is not a SynthID detector
|
||||
and is not in `identify`.
|
||||
|
||||
Separately, the
|
||||
best independently fitted spectral model relearned phase and magnitude from four of our
|
||||
positives while using third-party candidate coordinates; its second frozen
|
||||
epoch had zero false positives on 279 new exact-size external images and
|
||||
detected the one new confirmed positive used for validation. An additional
|
||||
@@ -499,6 +515,10 @@ was false; the resistance was that region-rescrub shielding, since removed.
|
||||
|
||||
### 2.3 Removal attacks and forensic detectability
|
||||
|
||||
This project's OpenAI oracle campaign, including closed quiet removers, is
|
||||
[synthid-removal-research.md](synthid-removal-research.md). The literature
|
||||
below is independent of that log.
|
||||
|
||||
The paper arXiv:2605.09203 ("Removing the Watermark Is Not Enough",
|
||||
Goonatilake & Ateniese, 2026) evaluates 6 removal attacks against a ResNet-50
|
||||
forensic detector. All attacks defeat the watermark verifier but are detected
|
||||
|
||||
@@ -187,7 +187,8 @@ OpenAI's API documentation says not to use repeated queries to reverse-engineer,
|
||||
or evade a watermark. Using it as an adaptive research oracle therefore requires explicit
|
||||
authorization. Without that authorization it must not become a training loss, search loop,
|
||||
or automated removal gate. The provider-specific detector and pixel-only removal research
|
||||
protocol is in [`synthid-detector-removal-plan.md`](synthid-detector-removal-plan.md).
|
||||
protocol is in [`synthid-detector-research.md`](synthid-detector-research.md);
|
||||
the chronological archive is [`synthid-detector-removal-plan.md`](synthid-detector-removal-plan.md).
|
||||
|
||||
Scope honestly: this tier certifies strength floors on a handful of images per vendor, and
|
||||
that is all it can do. See `docs/synthid.md`.
|
||||
|
||||
@@ -68,8 +68,8 @@ payloads. Removal remuxes either container through ffmpeg with stream copy.
|
||||
Amazon Titan Image Generator + Nova Canvas (Bedrock
|
||||
`DetectGeneratedContent` API), Kakao (new SynthID image adopter, May 2026),
|
||||
and NVIDIA Cosmos (SynthID video). No public payload decoder is available;
|
||||
unlike the project's calibrated-size SynthID carrier expert, these signals
|
||||
have no measured local detector here.
|
||||
unlike the project's calibrated-size generation-pipeline lattice expert,
|
||||
these signals have no measured local payload decoder here.
|
||||
- **C2PA 2.4 "Durable Content Credentials" (April 2026; verified against the spec) raise the bar for metadata stripping.** 2.4 defines soft bindings (an invisible watermark or a content fingerprint) plus a server-side manifest repository and a new `c2pa.repository-receipt` assertion. Per the spec: "if a C2PA manifest is removed from an asset, but a copy of that manifest remains in a provenance store elsewhere, the manifest and asset may be matched using available soft bindings." So our local `metadata --remove` deletes the *embedded* manifest, but a fingerprint/watermark soft binding can still re-link the image to its manifest in a repository server-side. Stripping the file is becoming necessary-but-not-sufficient against durable provenance. (Our parsers target the stable embedded-manifest format documented in C2PA 2.1 §11; that format is unchanged in 2.4 -- the new pieces are repository/soft-binding infra, not the on-file box layout, so no parser change is implied.) Spec: https://spec.c2pa.org/specifications/specifications/2.4/specs/C2PA_Specification.html We now READ the soft-binding `alg` (`C2PA_SOFT_BINDINGS` / `soft_binding_vendors_in`) to name the forensic-watermark vendor, and locally DECODE the one open scheme, Adobe TrustMark (`trustmark_detector`); the rest (Digimarc/Imatag/Steg.AI/...) stay name-only (proprietary decoders).
|
||||
- **Built in the dated batch:** soft-binding vendor detection, IPTC Photo
|
||||
Metadata AI-disclosure fields, C2PA detection and stripping for supported
|
||||
|
||||
Reference in New Issue
Block a user