Text-Watermarking für LLMs war von 2022 bis 2024 ein Forschungsthema mit einer berühmten Lücke: Der Erfinder konnte es nicht in Produktion bringen (Scott Aaronson prototypisierte sein Schema 2022 bei OpenAI, und die OpenAI-Führung entschied sich gegen den Rollout). Im August 2026 schloss sich diese Lücke von zwei Seiten gleichzeitig. Auf der geschlossenen Seite kündigte Anthropic an, dass Claude-Modelle gewässerten Text generieren, mit „einer Version des SynthID-Text-Ansatzes, den Google DeepMind 2024 in einem Nature-Paper veröffentlichte“1 — dem Paper von Dathathri et al., bis heute das einzige generative Text-Watermark mit Produktionseinsatz im großen Maßstab (Gemini, und jetzt Claude)2. Auf der Open-Engine-Seite liefert vLLM einen keyed Gumbel-Max-Watermarking-Modus mit einem Detektor, der ohne Modellgewichte läuft3. Zwei Konstruktionen derselben Aaronson-Idee von 2022, gelandet im selben rechtlichen Zeitfenster: Artikel 50(2) des EU AI Act, der seit dem 2. August 2026 gilt und Anbieter generativer Systeme verpflichtet, Outputs in maschinenlesbarem Format zu markieren45. Anthropic sagt den stillen Teil klar heraus: „we're applying watermarking globally at launch because we don't yet have a durable way to scope it by region“ (dt.: „wir wenden das Watermarking beim Launch global an, weil wir noch keinen dauerhaften Weg haben, es regional zu begrenzen“)1. Das Watermark existiert wegen eines europäischen Gesetzes — und es läuft überall.
Dieser Guide handelt nicht von der Policy-Debatte. Er prüft die Mathematik und den Silizium-Pfad, auf dem sie läuft: Was der Gumbel-Max-Trick genau ist und warum er ein exakter Sampler ist, wie ein Secret Key Sampling-Rauschen in ein detektierbares Signal verwandelt, ohne die Output-Verteilung zu verschieben, wie Detektionsstärke gemessen statt behauptet aussieht — und wo das Gesetz von Open-Weight-Deployments eine Eigenschaft verlangt, die sie strukturell nicht garantieren können. Jede Zahl unten stammt entweder wörtlich aus einer Primärquelle oder wurde in den Zellen gemessen und als solche gekennzeichnet.
1. Die rechtliche Uhr, exakt
Die Pflicht, im authentischen konsolidierten Text der Verordnung (EU) 2024/1689 (im Original Englisch; dt. Begriffe in Klammern):
Providers of AI systems, including general-purpose AI systems, generating synthetic audio, image, video or text content, shall ensure that the outputs of the AI system are marked in a machine-readable format and detectable as artificially generated or manipulated. Providers shall ensure their technical solutions are effective, interoperable, robust and reliable as far as this is technically feasible, taking into account the specificities and limitations of various types of content, the costs of implementation and the generally acknowledged state of the art4.
(„Anbieter von KI-Systemen ... stellen sicher, dass die Outputs des KI-Systems in maschinenlesbarem Format markiert und als künstlich erzeugt oder manipuliert erkennbar sind ... sofern dies technisch machbar ist, wobei die Besonderheiten und Grenzen verschiedener Inhaltsarten, die Implementierungskosten und den allgemein anerkannten Stand der Technik zu berücksichtigen sind, wie er in den einschlägigen technischen Normen zum Ausdruck kommen kann. Diese Pflicht gilt nicht, soweit die KI-Systeme eine unterstützende Funktion für die Standardbearbeitung ausführen oder die vom Betreiber bereitgestellten Eingabedaten oder deren Semantik nicht wesentlich verändern.“)
Drei Details dieses Textes tragen später die Arbeit. Erstens „machine-readable format and detectable“ (maschinenlesbar und erkennbar) — ein Watermark qualifiziert sich nur, wenn eine Maschine darauf testen kann, was genau eine keyed statistische Konstruktion liefert und eine unkeyed nicht. Zweitens der Vorbehalt „as far as this is technically feasible“ — der Gesetzgeber schrieb einen Entropie-Vorbehalt in den Artikel, ohne es zu wissen, denn Marking ist nur machbar, wo die Generierung Wahlmöglichkeiten hat (Abschnitt 4 zeigt das quantitativ). Drittens eine explizite Ausnahme am Ende des Absatzes für Systeme, die „an assistive function for standard editing“ erfüllen (eine assistive Funktion beim einfachen Korrekturlesen) oder die Eingabedaten nicht wesentlich verändern — Texte, die Claude nur durchliest, sind kein Marking-Ereignis, was fast Satz für Satz zu Anthropics eigener Limits-Sprache passt41.
Zum Timing: Der AI Act trat am 1. August 2024 in Kraft und gilt laut Artikel 113 „from 2 August 2026“5. Der Digital Omnibus, Verordnung (EU) 2026/1744 vom 8. Juli 2026, ergänzte für genau diese Pflicht eine Übergangsfrist: Erwägungsgrund 38 beschreibt die viermonatige Übergangsfrist, die als Artikel 111(4) kodifiziert ist — Anbieter, „die ihre Systeme vor dem 2. August 2026 auf dem Markt platziert haben" (providers who have already placed their systems on the market before the 2 August 2026), haben bis zum 2. Dezember 2026 Zeit6 — d. h. das Marking für Bestandssysteme muss bis zum 2. Dezember 2026 stehen, während Systeme, die nach dem 2. August 2026 auf den Markt kamen, es sofort schuldeten. Anthropics Rollout folgt exakt dieser Form: neue Modelle ab Launch gewässert, und „the EU law includes a transition period for Anthropic models launched before August 2, 2026, and we're working to add watermarking for those models as well“ (das EU-Recht enthält eine Übergangsfrist für Anthropic-Modelle, die vor dem 2. August 2026 gestartet sind; wir arbeiten daran, auch für diese Modelle Watermarking zu ergänzen)1. Anthropic unterzeichnete mit „around 190 total signatories“ (rund 190 Unterzeichnern insgesamt) im Juli 2026 den EU-Code of Practice on Transparency of AI-Generated Content1 — das Instrument, mit dem das AI Office der Kommission die Detektions- und Kennzeichnungspflichten aus Artikel 50(7) operativ macht.
2. Der Gumbel-Max-Trick: exaktes Sampling aus additivem Rauschen
Jeder autoregressive LLM-Decoder beendet einen Forward-Pass mit einer Verteilung über das Vokabular, und Sampling ist der Schritt, der diese Verteilung in ein Token verwandelt. Die klassische Methode ist die Inversion der kumulativen Verteilungsfunktion: eine gleichverteilte Zufallszahl ziehen und die kumulative Verteilung entlanglaufen. Der Gumbel-Max-Trick ist die weniger offensichtliche Entsprechung: Addiert man zu jedem Log-Wahrscheinlichkeit (log p-Wert) unabhängiges gumbel-verteiltes Rauschen und nimmt das argmax, so ist der Gewinner exakt kategorial verteilt wie die Ausgangsverteilung. Das ist die ganze Maschine, auf der beide Watermarks laufen — prüfen wir sie also statt sie zu behaupten. Die Gumbel(0,1)-Verteilung hat die Verteilungsfunktion F(x) = exp(-exp(-x)); wenn G.i iid Gumbel sind, dann gilt: P(argmax aus log p.i + G.i = k) = p.k — beweisbar über die Max-Stabilität der Gumbel-Familie (das Maximum iid Gumbels, verschoben um log n, ist wieder Gumbel — dieselbe Eigenschaft, die den Trick überhaupt trägt).
# Cell 1: Gumbel-max trick vs naive CDF inversion, 200,000 draws
import math, random
V = 4 # tiny 4-token vocabulary
probs = [0.55, 0.25, 0.15, 0.05] # the model's next-token distribution
cum = []
s = 0.0
for p in probs:
s += p
cum.append(s)
cum[-1] = 1.0 # guard against float drift
def sample_cdf(r): # naive inversion: first i with r < cum[i]
for i, c in enumerate(cum):
if r < c:
return i
return V - 1
def gumbel(rng): # G_i ~ Gumbel(0,1) via inverse CDF:
u = rng.random() # F(x) = exp(-exp(-x)) => x = -ln(-ln u)
return -math.log(-math.log(u))
def sample_gumbel_max(rng): # argmax_i ( log p_i + G_i )
best, best_score = -1, -math.inf
for i in range(V):
score = math.log(probs[i]) + gumbel(rng)
if score > best_score:
best, best_score = i, score
return best
N = 200000
rng = random.Random(2026)
c_cnt = [0] * V
g_cnt = [0] * V
for _ in range(N):
c_cnt[sample_cdf(rng.random())] += 1
g_cnt[sample_gumbel_max(rng)] += 1
print("Empirical frequencies over", N, "draws (analytic in last column)")
print("")
print(f"{'token':>6} {'analytic':>10} {'CDF inv':>10} {'Gumbel-max':>11}")
for i in range(V):
print(f"{i:>6} {probs[i]:>10.4f} {c_cnt[i]/N:>10.4f} {g_cnt[i]/N:>11.4f}")
print("")
print("max |CDF - analytic| =", f"{max(abs(c_cnt[i]/N - probs[i]) for i in range(V)):.5f}")
print("max |Gum - analytic| =", f"{max(abs(g_cnt[i]/N - probs[i]) for i in range(V)):.5f}")
# Max-stability check: max of two iid Gumbels is Gumbel(0,1) again,
# up to the shift log(2): F_max(x) = F(x)^2 = exp(-2 exp(-x))
# = exp(-exp(-(x - ln 2)))
rng2 = random.Random(7)
m = [0] * 5 # histogram bins over [-1, 3)
hits = 0
TOTAL = 100000
for _ in range(TOTAL):
x = max(gumbel(rng2), gumbel(rng2))
if 0.0 <= x < 1.0:
hits += 1
b = hits / TOTAL
a = math.exp(-2 * math.exp(-1)) - math.exp(-2) # F_max(1)-F_max(0) = F(1)^2 - F(0)^2
print("")
print(f"P(0 <= max of 2 Gumbels < 1): empirical {b:.4f} vs exact exp(-2e^-1)-exp(-2) = {a:.4f}")Empirical frequencies over 200000 draws (analytic in last column)
token analytic CDF inv Gumbel-max
0 0.5500 0.5506 0.5495
1 0.2500 0.2507 0.2510
2 0.1500 0.1490 0.1498
3 0.0500 0.0497 0.0498
max |CDF - analytic| = 0.00101
max |Gum - analytic| = 0.00100
P(0 <= max of 2 Gumbels < 1): empirical 0.3446 vs exact exp(-2e^-1)-exp(-2) = 0.3438(Eigene Messung, /usr/bin/python3.) Beide Sampler landen über 200.000 Ziehungen innerhalb von 0,001 der analytischen Verteilung, und das Max-Stabilitäts-Intervall trifft seine geschlossene Form auf drei Dezimalen. „Exakt“ arbeitet hier redlich: Keyless Gumbel-Rauschen ändert nichts an der induzierten Token-Verteilung. Woher kommt also ein Watermark? Indem man die Quelle des Rauschens ändert, nicht seine Verteilung.
3. Das Rauschen keyed machen: Aaronson (2022), SynthID-Text (2024), vLLM (2026)
Aaronsons Proposal von 2022 — „soweit ich weiß, der erste LLM-Watermarking-Vorschlag“, wie er anlässlich von Anthropics Deployment zurückblickt — ist die minimale Bewegung: Ersetze das iid Gumbel-Rauschen durch pseudorandom Rauschen, abgeleitet aus einem Secret Key und dem jüngsten Kontext. Dann werden die „ Zufalls“-Wahlen deterministisch gegeben dem Key; wer den Key hält, kann jeden Rauschwert neu ableiten und Übereinstimmung testen, und ein Außenstehender sieht eine unveränderte Verteilung. Wie Anthropic die Familie zusammenfasst: „the watermark only changes the source of the randomness used to pick among words“ (das Watermark ändert nur die Quelle des Zufalls, mit dem unter Wörtern gewählt wird)1. Aaronson berichtet, dass Hendrik Kirchner den Prototyp bei OpenAI baute und testete, dass die OpenAI-Führung sich gegen den Einsatz entschied, und dass Christ, Gunn und Zamir das Schema anschließend in Richtung kryptographischer Ununterscheidbarkeit verstärkten7. Eine parallele Linie von 2023, Kirchenbauer et al.s Green-/Red-List-Watermark (arXiv:2301.10226, ICML 2023), ging einen gröberen, aber billigeren Weg — das weiche Bevorzugen einer hash-ausgewählten „grünen Liste“ —, was die Verteilung leicht verschiebt8.
Die produktionsreifen Nachfahren keyen das Rauschen auf zwei verschiedene Arten.
SynthID-Text (Dathathri et al., Nature 634, 2024) — Tournament-Sampling. Der Random-Seed-Generator nutzt die Sliding-Window-Methode: „the random seed is a hash of the most recent H tokens ... along with the watermarking key“ (der Seed ist ein Hash der H letzten Tokens zusammen mit dem Watermarking-Key), mit H = 4. Der Seed speist m unabhängige pseudorandom Watermarking-Funktionen, die jedem Kandidaten-Token einen g-Wert zuweisen (eine 0 oder 1, also Bernoulli). Die Generierung läuft dann ein K.o.-Turnier: Man zieht M = 2^m Kandidaten-Tokens aus der Verteilung des Modells selbst, paart sie, und in jedem Paar wird „the token with the higher score under g_1 is selected ... any ties are broken randomly“ (das Token mit dem höheren g_1-Wert wird gewählt, Gleichstände zufällig gebrochen); die Gewinner werden neu gepaart und unter g_2 bewertet, bis durch g_m; der letzte Gewinner wird das Output-Token2. Das Paper-Default ist m = 30 (mit ihrer Spekulative-Sampling-Integration wird das leistbar). Die Detektion braucht nur den tokenisierten Text und den Key: jeden Seed aus dem Sliding-Window rekonstruieren, die g-Werte der emittierten Tokens bewerten (eine einfache Scoring-Funktion ist der schlichte Mittelwert über Schritte und Schichten; das Paper nutzt standardmäßig seine Bayessche Scoring-Funktion) und mit einem Schwellwert vergleichen. Weil jeder Kandidat aus der Verteilung des Modells selbst gezogen wurde und das Turnier nur zwischen gleichplausiblen Zügen neu gewichtet, lässt die nicht-verzerrende Konfiguration die marginale Token-Verteilung intakt — eine Eigenschaft, die Google an „nearly 20 million“ (fast 20 Millionen) Live-Gemini-Antworten ohne statistisch signifikanten Unterschied in den Nutzerbewertungen validierte21.
vLLM — keyed Gumbel-Max. Die Open-Engine übernimmt Aaronsons Konstruktion im Wesentlichen direkt. Beim Engine-Start akzeptiert sie --watermark-config \{"algorithm":"gumbel","key":42\}; „Gumbel-max derives a deterministic pseudorandom value from the key, prior token context, and every candidate token, then uses the resulting Gumbel noise for categorical sampling“ (Gumbel-Max leitet einen deterministischen pseudorandom Wert aus Key, vorangegangenem Token-Kontext und jedem Kandidaten-Token ab und nutzt das resultierende Gumbel-Rauschen für das kategoriale Sampling) — ein Philox-PRF, gekeyt mit dem Secret und den vorherigen context_width = 4 Tokens39. Greedy-Requests (Temperatur 0) umgehen das Watermarking komplett; wiederholte Kontexte werden dedupliziert, wobei die Docs für das Single-Sequence-Argument Abschnitt G.3 der SynthID-Text-Supplementary-Materials zitieren — dieselbe Sorge, die das Nature-Paper durch Rückfall auf gewöhnliches Sampling bei wiederholtem Kontextfenster löst3. Die Detektion ist wie bei SynthID-Text gewichtsfrei: Ein GumbelWatermarkDetector(key=42, prf="philox"), angewandt auf die Token-ID-Liste, liefert p-Wert und Urteil — ein Downstream-Akteur kann einen Stream verifizieren, ohne das Modell zu kennen, nur mit dem Key3.
Beide sind strukturell derselbe Satz: Das argmax aus (log p plus keyed pseudorandom Gumbels) ist gegeben dem Key-Rauschen exakt kategorial — und nur durch die Linse des Keys in der Aggregatstatistik unterscheidbar. Jetzt die Detektionsseite messen.
4. Detektionsstärke, gemessen — und Anthropics Limits-Sektion, eingepreist
Das Experiment unten (eigene Messung, /usr/bin/python3, fixe Seeds) implementiert ein minimales keyed-Gumbel-Watermark über eine flache 32-Token-Verteilung: An jeder Position liefert ein keyed PRF (HMAC-SHA256 über den Key, die vier vorherigen Tokens, die Position und das Kandidaten-Token) das Gumbel-Rauschen, und das argmax gewinnt. Der Detektor rekonstruiert dasselbe Rauschen und bewertet das emittierte Token gegen die Rauschverteilung der Position — Zelle 2 gegen den Positionsmittelwert, Zelle 3 gegen das Positionsmaximum über das Vokabular — null, wenn der Favorit des Keys gewann, im Mittel negativ für ungewässerten Text. Der Null-Mittelwert ist kein Mysterium: E[ein Gumbel] ist die Euler–Mascheroni-Konstante γ ≈ 0,5772, und E[Maximum aus n iid Gumbels] ist γ + ln n (Max-Stabilität) — für ein gleichverteilt gewähltes Token aus V = 32 hat die Lücke „gewählt minus Maximum“ also exakt den Erwartungswert -ln 32 ≈ -3,4657, was die Kalibrierung unten bestätigt (-3.4621/-3.4582/-3.4663 bei N = 50/200/500).
# Cell 2: keyed-PRF Gumbel sampling vs unwatermarked streams
import math, hmac, hashlib
KEY = b"secret-deployment-key"
CTX = 4
def gumbel_from(prf_value): # uniform u in (0,1) -> Gumbel(0,1)
u = (prf_value % 1000003 + 1) / 1000004.0
return -math.log(-math.log(u))
def prf(items): # keyed PRF: HMAC-SHA256(key, ctx || token)
msg = b"|".join(str(t).encode() for t in items)
d = hmac.new(KEY, msg, hashlib.sha256).digest()
return int.from_bytes(d[:8], "big")
V = 32
probs = [1.0 / V] * V # flat: every choice is "low-stakes"
def gen_watermarked(n, seed):
stream, context = [], list(range(CTX))
for pos in range(n):
context_seed = tuple(context)
best, best_score = -1, -math.inf
for tok in range(V):
score = math.log(probs[tok]) + gumbel_from(prf(context_seed + (pos, tok)))
if score > best_score:
best, best_score = tok, score
stream.append(best)
context = context[1:] + [best]
return stream
def gen_plain(n, seed):
import random
rng = random.Random(seed)
return [rng.randrange(V) for _ in range(n)]
def logl_gap(stream): # detector: sum over positions of
gap, hits = 0.0, 0 # log p_PRF(winner) - log(1/V) statistic
context = list(range(CTX))
for pos, tok in enumerate(stream):
scores = [gumbel_from(prf(tuple(context) + (pos, t))) for t in range(V)]
gap += scores[tok] - sum(scores) / V
context = context[1:] + [tok]
return gap
for N in (200, 500):
wm = gen_watermarked(N, 1)
pl = gen_plain(N, 99)
s_wm = logl_gap(wm)
s_pl = logl_gap(pl)
print(f"N={N}: watermarked stream score S={s_wm:9.2f} | plain random stream S={s_pl:9.2f}")N=200: watermarked stream score S= 699.60 | plain random stream S= -8.64
N=500: watermarked stream score S= 1727.02 | plain random stream S= -49.56Der gewässerte Stream akkumuliert grob N × ln 32 ≈ 693 / 1733 Einheiten Überschuss-Score (beobachtet: 699.60 / 1727.02); die ungewässerten Streams liegen um null herum (-8.64, -49.56). Bei einer flachen 32-Wege-Wahl ist das Signal gewaltig — das ist der Bestfall, jede Position maximal „low-stakes“. Die eigentliche Frage ist, was bei spärlichem Marking passiert, und genau da lebt Anthropics eigene Limits-Sektion. Dieselbe Maschine mit nur einem Bruchteil gewässerter Positionen — der Rest steht für die wahlfreien Strecken, die Anthropic beschreibt („Isaac Newton's most famous work was called Principia“ — es gibt nur eine richtige Fortsetzung, „so the watermark would have nothing to act on“, also hätte das Watermark nichts, worauf es wirken kann) — und Detektion gegen 200 ungewässerte Streams pro Textlänge kalibriert:
# Cell 3: sparse marking, short samples, thresholds, false positives
import math, hmac, hashlib, random
KEY = b"secret-deployment-key"
CTX = 4
V = 32
def prf(items): # keyed PRF, same as cell 2
msg = b"|".join(str(t).encode() for t in items)
d = hmac.new(KEY, msg, hashlib.sha256).digest()
return int.from_bytes(d[:8], "big")
def gumbel_from(prf_value):
u = (prf_value % 1000003 + 1) / 1000004.0
return -math.log(-math.log(u))
def gen(n, seed, mark_frac=1.0):
# mark_frac = fraction of positions watermarked; the rest are plain random
# picks, standing in for choice-free stretches ("Principia ... Mathematica":
# the watermark has nothing to act on because there is nothing to choose).
rng = random.Random(seed ^ int(mark_frac * 10000))
stream, context = [], list(range(CTX))
for pos in range(n):
if rng.random() < mark_frac:
cs = tuple(context)
best, bs = -1, -math.inf
for tok in range(V):
sc = gumbel_from(prf(cs + (pos, tok)))
if sc > bs:
best, bs = tok, sc
else:
best = rng.randrange(V)
stream.append(best)
context = context[1:] + [best]
return stream
def stat(stream): # detector statistic: mean over positions of
context = list(range(CTX)) # PRF-Gumbel(chosen) minus the position max
s = 0.0 # over the vocabulary; 0 when the key's
for pos, tok in enumerate(stream): # favorite won, ~ -3.47 on average for
scores = [gumbel_from(prf(tuple(context) + (pos, t))) for t in range(V)]
s += scores[tok] - max(scores) # unwatermarked picks (E[max of 32] - E[Gumbel])
context = context[1:] + [tok]
return s / len(stream)
# Calibrate the unwatermarked (null) distribution empirically, per sample size:
cal = {}
for n in (50, 200, 500):
vals = [stat(gen(n, 70000 + s, mark_frac=0.0)) for s in range(200)]
mu = sum(vals) / len(vals)
sd = (sum((x - mu) ** 2 for x in vals) / (len(vals) - 1)) ** 0.5
cal[n] = (mu, sd)
def zval(stream): # positive z = consistent with the key
mu, sd = cal[len(stream)]
return (stat(stream) - mu) / sd
print("Detection z vs empirical plain null (positive = consistent with the key):")
for n, sp in ((50, 5101), (200, 5202), (500, 5303)):
print(f" N={n:>4}: plain z={zval(gen(n, sp, mark_frac=0.0)):+8.2f} fully marked z={zval(gen(n, sp, mark_frac=1.0)):+8.2f}")
print("")
print("Null calibration (200 plain streams per N): the null sharpens as 1/sqrt(N),")
print("so a few marked positions that drown at N=50 can still separate at N=500:")
for n in (50, 200, 500):
mu, sd = cal[n]
print(f" N={n:>4}: mu={mu:.4f} sd={sd:.4f}")
print("")
print("Sparse marking: mean z over 20 trials per cell (f = fraction of positions marked)")
print(f"{'f':>5} {'N=50':>8} {'N=500':>8}")
for f in (1.0, 0.5, 0.2):
z50 = sum(zval(gen(50, 6000 + s, mark_frac=f)) for s in range(20)) / 20
z500 = sum(zval(gen(500, 6000 + s, mark_frac=f)) for s in range(20)) / 20
print(f"{f:>5.1f} {z50:>+8.1f} {z500:>+8.1f}")
print("")
print("Proofreading case, N=200: only 5% of positions are actually the editor's")
print("choices (grammar fixes in a human text); mean z over 20 trials:")
zp = sum(zval(gen(200, 8000 + s, mark_frac=0.05)) for s in range(20)) / 20
print(f" f=0.05 -> mean z = {zp:+.2f} (compare f=1.0 at N=200 above; even a")
print(f" loose tau=+2 would call most such texts unwatermarked)")
print("")
print("Threshold sweep on the z-scale, N=500, f=0.2 (100 marked positions):")
for tau in (2, 3, 4):
tpr = sum(1 for s in range(100) if zval(gen(500, 9000 + s, mark_frac=0.2)) >= tau) / 100
fpr = sum(1 for s in range(2000) if zval(gen(500, 80000 + s, mark_frac=0.0)) >= tau) / 2000
print(f" tau=z {tau}: TPR={tpr:.3f} FPR={fpr:.4f}")
print("")
print("Tail math -- false positives if the null were exactly normal (it is not):")
for zz in (2, 3, 4, 5):
print(f" threshold at z=+{zz}: one-sided normal tail P = {0.5 * math.erfc(zz / math.sqrt(2)):.2e}")Detection z vs empirical plain null (positive = consistent with the key):
N= 50: plain z= -1.33 fully marked z= +13.75
N= 200: plain z= +0.07 fully marked z= +28.35
N= 500: plain z= +0.70 fully marked z= +46.95
Null calibration (200 plain streams per N): the null sharpens as 1/sqrt(N),
so a few marked positions that drown at N=50 can still separate at N=500:
N= 50: mu=-3.4621 sd=0.2518
N= 200: mu=-3.4582 sd=0.1220
N= 500: mu=-3.4663 sd=0.0738
Sparse marking: mean z over 20 trials per cell (f = fraction of positions marked)
f N=50 N=500
1.0 +13.8 +47.0
0.5 +6.9 +23.7
0.2 +3.0 +9.2
Proofreading case, N=200: only 5% of positions are actually the editor's
choices (grammar fixes in a human text); mean z over 20 trials:
f=0.05 -> mean z = +1.15 (compare f=1.0 at N=200 above; even a
loose tau=+2 would call most such texts unwatermarked)
Threshold sweep on the z-scale, N=500, f=0.2 (100 marked positions):
tau=z 2: TPR=1.000 FPR=0.0310
tau=z 3: TPR=1.000 FPR=0.0030
tau=z 4: TPR=1.000 FPR=0.0000
Tail math -- false positives if the null were exactly normal (it is not):
threshold at z=+2: one-sided normal tail P = 2.28e-02
threshold at z=+3: one-sided normal tail P = 1.35e-03
threshold at z=+4: one-sided normal tail P = 3.17e-05
threshold at z=+5: one-sided normal tail P = 2.87e-07Lies die Tabelle gegen Anthropics Limitations-Sektion, Klausel für Klausel — dies ist unsere Messung, nicht ihre interne Datenlage, aber die Formen, die sie einräumt, sind exakt die Formen, die die Mathematik produziert:
- „Detecting a watermark also doesn't work well on small samples, where there are fewer word choices and thus less information to go on“ (Detektion funktioniert bei kleinen Stichproben nicht gut, wo es weniger Wortwahlen und thus weniger Information gibt)1. In den Zellen: Bei vollem Marking ist das Signal selbst bei N = 50 überwältigend (z = +13.75). Nicht die rohe Länge tötet die Detektion — sondern Länge mal Markierungsdichte. Bei f = 0,2 landet N = 50 bei einem mittleren z von +3.0, grenzwertig gegen eine tau-=-4-Regel; derselbe spärliche Stream bei N = 500 steigt auf z = +9.2. „As a passage increases in length, confidence about Claude's involvement increases too“ (mit der Länge einer Passage steigt das Vertrauen in Claudes Beteiligung)1 — dieser Satz ist eine 1/√N-Aussage, und die Kalibrierungszeile zeigt den Mechanismus: sd schrumpft von 0.2518 auf 0.0738 zwischen N = 50 und N = 500.
- „Watermarking is sparser on factual passages where there are fewer choices that can be made without decreasing the accuracy of the text“ (Watermarking ist dünner in faktischen Passagen mit weniger Wahlmöglichkeiten, die sich ohne Genauigkeitsverlust des Textes treffen lassen)1. Die f-Spalte ist dieses Zitat als Arithmetik. Das Nature-Paper sagt es informationstheoretisch: „Tournament sampling performs better when there is more entropy in the LLM distribution, and is less effective when there is less entropy“2.
- Korrekturlesen: „because nearly all the words are the person's, there's very little (if anything) for the watermark to attach to“ (weil fast alle Wörter die der Person sind, gibt es sehr wenig, woran das Watermark haften kann)1. Bei f = 0,05 (ein leicht redigierter menschlicher Text, N = 200) beträgt das mittlere z +1.15 — mitten im Rauschband von Klartext, und beachte: Genau dieser Fall ist von der Marking-Pflicht des Artikels 50(2) selbst ausgenommen („assistive function for standard editing“)4. Statut und Statistik sind sich einig.
- Leichtes Editieren vs. Umschreiben: „Light editing probably won't remove the watermark completely; a complete rewrite where every word is replaced will“ (Leichtes Editieren entfernt das Watermark wahrscheinlich nicht vollständig; eine vollständige Umschreibung, bei der jedes Wort ersetzt wird, schon)1. Leichte Edits stören die Kontextfenster lokal; Key-Hits — Positionen, an denen das emittierte Token noch zur rekonstruierten PRF-Rauschstruktur passt — überleben, weil die meisten Kontextfenster und ihre Gewinner unangetastet bleiben. Eine vollständige Umschreibung würfelt jedes Token unter * anderem* Rauschen (oder keinem) neu aus, und die Korrelation mit deinem Key fallt auf null. Es gibt keine Klippe; das Signal zerfällt mit dem Anteil überlebender markierter Wahlen — exakt die f-Spalte rückwärts.
- Und die Mehrdeutigkeit, die der Detektor genuin nicht auflösen kann: „A watermark can only determine that Claude was likely involved with the content at some point. It cannot distinguish 'Claude wrote this' from 'Claude heavily edited this'“ (Ein Watermark kann nur bestimmen, dass Claude irgendwann wahrscheinlich beteiligt war; es kann nicht unterscheiden, ob Claude dies schrieb oder stark überarbeitete)1.
Der Schwellwert-Sweep ergänzt den compliance-relevanten Trade: Bei 100 markierten von 500 Positionen schiebt tau von z = 2 auf 4 die FPR von 3,10% auf 0,00% (empirisch, auf 2000 Null-Streams) bei unverändertem TPR = 1.000. Die Normal-Tail-Zeile ist die Intuitions-Linie des Planers — eine z-=-4-Regel hat eine False-Positive-Rate von 3.17e-05, wenn die Null normal ist, und die praktische Lehre aus der empirischen Kalibrierung ist: Nimm das niemals an.
5. Die Compliance-Asymmetrie, die niemand eingepreist hat
Artikel 50(2) verpflichtet Anbieter. Marking ist eine Anbieter-Eigenschaft, und sie teilt den Markt an der Open/Closed-Grenze ungleich.
Geschlossene Anbieter können sie einseitig liefern. Anthropic hält die Gewichte, den Endpunkt und den Key. Sie wendet das Watermarking global an — laut eigener Aussage auf Modellebene, sodass es präsent ist, egal von welcher Claude-Fläche der Text stammt — und die Marking-Pflicht ist per Tastenanschlag erfüllt: Outputs vom Endpunkt sind markiert, Punkt. Wo sie Ermessen ausübt, ist der Detektionszugang: Die Detection-API ist „in private preview“ (in privater Vorschau), verfügbar für „eligible organizations as required under EU law“ (berechtigte Organisationen, wie es das EU-Recht verlangt) — Regulierungsbehörden, Strafverfolgung, Medien, Faktenchecks, Forschung — plus verpflichtete Unternehmen; „we plan to expand access over time“ (wir planen, den Zugang über die Zeit auszuweiten)1. Die Marke ist universell; der Beweis der Marke ist Gated. Das ist eine Policy-Entscheidung, die das Statut zulässt — Artikel 50(2) verlangt, dass Outputs „detectable“ sind, nicht dass jeder den Detektor bekommt —, aber sie verwandelt ein Transparenz-Instrument in ein institutionelles.
Open-Weight-Deployments stehen vor dem Spiegelbild, in drei Teilen.
- Ein Watermark auf offenen Gewichten ist ein Angebot, keine Garantie. Sind die Gewichte herunterladbar, hat der Anbieter nichts darüber markiert, was andere damit servieren. vLLMs Watermarks sind real und gut gebaut, aber sie keyed auf die Konfiguration des Betreibers; eine zweite Bereitstellung derselben Gewichte ohne
--watermark-config, oder ein Fine-Tune darüber, generiert unter anderem Rauschen oder keinem. Die Anbieterpflicht des Statuts reist mit den Gewichten nur so weit, wie der Anbieter gewässerte Defaults und eigene Serving-Endpunkte mitliefert — sie reist nicht zu Downstream-Re-Serves. (Die Open-Source-Ausnahme in Artikel 2(12) des AI Act rettet das nicht: Sie hält Artikel-50-Pflichten für darunterfallende Systeme ausdrücklich aufrecht4.) - Umgekehrt KANN der Betreiber die Herkunft seines eigenen Streams beweisen. Das ist die unterpreiste Chance auf der offenen Seite. Weil die Detektion nur Key und Tokenizer braucht, kann jeder, der einen vLLM-Endpunkt betreibt, das Watermark anlassen, Commitments publizieren und gewichtsfreie Beweise erzeugen, dass ein gegebener Output von der eigenen Infrastruktur stammt — eine Fähigkeit, die kein C2PA-Metadatenlabel für Text gibt, weil es keine Textdatei zu signieren gibt31. Open-Serving kann Marking nicht garantieren, aber Attribuierbarkeit dessen, was es selbst serviert hat — was einen realen Teil der Artikel-50(2)-Compliance von Betreibern abdeckt, die selbst Anbieter ihres gewrappten Produkts sind.
- Niemand kann Abwesenheit beweisen. Ein negatives Watermark-Urteil beweist nur „mit diesem Key nicht detektiert“ — auf kurzen Texten ist das ehrliche Urteil echt schwach (Abschnitt 4), und ein Angreifer, der durch irgendein ungewässertes Modell paraphrasiert, streicht das Signal ohnehin, wie Aaronson zu seiner eigenen Schema-Familie nüchtern einräumt7. Die Asymmetrie schneidet also zwei Wege: Geschlossene Endpunkte erzeugen Marken, die stark sind, aber nur durch einen Gatekeeper testbar; offene Deployments erzeugen Marken, die jeder mit dem Key testen kann, die aber stromabwärts niemanden binden.
Das ist die Asymmetrie, die der Markt nicht eingepreist hat: Artikel 50(2) verlangt eine Eigenschaft, die genau dort billig und robust ist, wo der Anbieter bereits den gesamten Pfad von Logits zu Bytes kontrolliert — und anderswo nur verfügbar ist: Opt-in, beim Fine-Tune verlierbarer Key, durch Paraphrasierung streichbar. Die rund 190 Unterzeichner des Code of Practice sind überwiegend Entitäten, die ihren Serving-Pfad kontrollieren1. Für das offene Ökosystem schuf dasselbe Statut, das vLLMs Watermarking-PR-Budget finanzierte, eine Pflicht, die die Vorzeige-Open-Deployments für ihre Downstream-Nutzer nicht vollständig erfüllen können — nur für den eigenen Stream gute Faith demonstrieren.
6. Fazit
Was Watermarking wert ist, ehrlich gemessen: eine starke, praktisch kostenlose, am Rand verteilungserhaltende Marking-Technologie für kontrollierte Endpunkte des Anbieters. Die Gumbel-Max-Mathematik ist exakt (Zelle 1), die keyed Version trennt sauber selbst bei bescheidenen Textlängen (Zellen 2-3: z = +28.35 bei N = 200 voll markiert; TPR = 1.000 bei FPR = 0.0030 mit 100 markierten Positionen), die Live-Evidenz im Gemini-Maßstab — fast 20 Millionen Antworten ohne erkennbaren Qualitätsunterschied — ist die stärkste Einsatzdaten, die das Feld hat2, und Anthropics Nutzung davon kostet keine Extra-Tokens, keine nennenswerte Latenz und trägt keine nutzeridentifizierende Information1.
Was es nicht ist: Provenance (Herkunftsnachweis). Es kann nicht attribuieren, nicht individualisieren, überlebt keinen motivierten Umschreiber — und es zerfällt genau dort, wo Texte kurz, faktisch oder kaum maschinenberührt sind: die drei Fälle, denen ein Compliance-Programm am meisten traut. „What is the likelihood this was partly written by Claude?“ ist die einzige Frage, die Anthropic für ihren Key beansprucht1; die ehrliche Antwort ist eine monotone Funktion von Länge mal Wahldichte, und die drei Zellen oben sind diese Funktion, ausgerechnet.
Und der Teil, den niemand eingepreist hat: Das Gesetz macht den strukturellen Vorteil der geschlossenen Seite — Key, Endpunkt, gegateter Verifizierer — jetzt zu einem Compliance-Vermögenswert, während Open-Weight-Deployments ein Werkzeug bekommen, das ihre eigene Integrität beweist, aber niemand sonst bindet. Watermarking ist ausgeliefert. Die Asymmetrie liefert es mit.
7. Quellen
Footnotes
-
Anthropic: How Claude's text watermarking works, 14. August 2026 (aktualisiert 1. September 2026), https://www.anthropic.com/news/claude-text-watermark. Alle Zitate wörtlich von der Live-Seite, abgerufen am 25. September 2026. Deutschsprachige Wiedergaben in Klammer sind Übersetzungen des Verfassers. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13 ↩14 ↩15 ↩16 ↩17 ↩18
-
Sumanth Dathathri, Abigail See, Sumedh Ghaisas, Po-Sen Huang, Rob McAdam, Johannes Welbl, Vandana Bachani, Alex Kaskasoli, Robert Stanforth, Tatiana Matejovicova, Jamie Hayes, Nidhi Vyas, Majd Al Merey, Jonah Brown-Cohen, Rudy Bunel, Borja Balle, Taylan Cemgil, Zahra Ahmed, Kitty Stacpoole, Ilia Shumailov, Ciprian Baetu, Sven Gowal, Demis Hassabis, Pushmeet Kohli: Scalable watermarking for identifying large language model outputs, Nature 634, 818–823, 23. Oktober 2024, DOI 10.1038/s41586-024-08025-4, Volltext via PubMed Central PMC11499265. Turnier-Beschreibung, H = 4, m = 30, g-Werte, Scoring-Funktionen und das Live-Experiment mit 20 Millionen Antworten stammen aus den Main- und Methods-Sektionen, abgerufen am 25. September 2026. ↩ ↩2 ↩3 ↩4 ↩5
-
vLLM-Dokumentation: Text watermarking, https://docs.vllm.ai/en/latest/features/watermarking, Teil der in vLLM RFC #53916 getrackten Arbeit, abgerufen am 25. September 2026. Flagnamen, Defaults (context_width = 4, Philox-PRF), Greedy-Bypass, Kontext-Deduplizierung und die Detektor-API stammen wörtlich von der Live-Dokumentationsseite. ↩ ↩2 ↩3 ↩4 ↩5
-
Verordnung (EU) 2024/1689 (AI Act), Artikel 50(2) und Artikel 2(12), konsolidierter Text CELEX 02024R1689 vom 27. Juli 2026, https://eur-lex.europa.eu/eli/reg/2024/1689/oj. Artikel 50(2) wörtlich zitiert (im englischen Original). ↩ ↩2 ↩3 ↩4 ↩5
-
Verordnung (EU) 2024/1689, Artikel 113: Inkrafttreten am zwanzigsten Tag nach Veröffentlichung (in Kraft seit 1. August 2024); „It shall apply from 2 August 2026“. ↩ ↩2
-
Verordnung (EU) 2026/1744 (Digital Omnibus on AI) vom 8. Juli 2026, veröffentlicht im ABl. am 24. Juli 2026, Erwägungsgrund 38: die viermonatige Übergangsfrist für die Marking-Pflichten aus Artikel 50(2), begrenzt auf Anbieter, die ihre Systeme „before the 2 August 2026“ auf dem Markt platziert haben — das Marking solcher Systeme ist bis zum 2. Dezember 2026 fällig. https://eur-lex.europa.eu/eli/reg/2026/1744/oj ↩
-
Scott Aaronson: Anthropic's LLM watermarking, Shtetl-Optimized, 22. August 2026, https://scottaaronson.blog/?p=10032, dazu die Materialien von 2022: Watermarking of GPT Outputs (Talk-Slides mit Hendrik Kirchner, https://www.scottaaronson.com/talks/watermark.ppt) und der TechCrunch-Bericht vom 10. Dezember 2022 über seine UT-Austin-Vorlesung. ↩ ↩2
-
John Kirchenbauer, Jonas Geiping, Yuxin Wen, Jonathan Katz, Ian Miers, Tom Goldstein: A Watermark for Large Language Models, arXiv:2301.10226, ICML 2023. Green-List-Framework und der „negligible impact on text quality“-Anspruch stammen aus dem Abstract, abgerufen am 25. September 2026. ↩
-
vLLM-API-Referenz: WatermarkConfig, https://docs.vllm.ai/en/latest/api/vllm/config/watermarking. Gumbel ist der Default-Algorithmus innerhalb einer aktivierten WatermarkConfig. ↩