[watermarking] golden tests for backwards compatibility (#56809)
Signed-off-by: Raphael Rialland <raphael.rialland@mistral.ai> Signed-off-by: Simon Veitner <sveitner@redhat.com> Co-authored-by: Simon Veitner <sveitner@redhat.com> Co-authored-by: OpenAI Codex <codex@openai.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Raphaël Rialland committed
Sep 26, 2026 at 00:01 UTC
4ccfe1239843998f9b3e109f159278dc0fcbf753
7 files changed
+3866
-3
.buildkite/test_areas/misc.yaml
+2
@@ -211,6 +211,7 @@ steps:
211
- vllm/utils/
212
- vllm/v1/
213
- tests/v1
214
+ - tests/watermarking
215
device: cpu-small
216
commands:
217
# split the test to avoid interference
@@ -222,6 +223,7 @@ steps:
223
- pytest -v -s -m 'cpu_test' v1/kv_connector/unit
224
- pytest -v -s -m 'cpu_test' v1/ec_connector/unit
225
- pytest -v -s -m 'cpu_test' v1/metrics
226
+ - pytest -v -s watermarking
227
228
- label: ":nvidia: (H200 MIG 18GB) Extract Hidden States Integration"
229
key: extract-hidden-states-integration
tests/watermarking/__init__.py
new
+2
@@ -0,0 +1,2 @@
1
+# SPDX-License-Identifier: Apache-2.0
2
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
tests/watermarking/generate_goldens.py
new
+24
@@ -0,0 +1,24 @@
1
+# SPDX-License-Identifier: Apache-2.0
2
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
+
4
+"""Regenerate tests/watermarking/watermarking_goldens.json."""
5
+
6
+import json
7
+from pathlib import Path
8
+
9
+from tests.watermarking.golden_candidates import golden_payload, validate_golden_guards
10
+
11
+GOLDENS_PATH = Path(__file__).with_name("watermarking_goldens.json")
12
+
13
+
14
+def main() -> None:
15
+ payload = golden_payload()
16
+ validate_golden_guards(payload["candidates"])
17
+ GOLDENS_PATH.write_text(
18
+ json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8"
19
+ )
20
+ print(f"wrote {len(payload['candidates'])} candidates to {GOLDENS_PATH}")
21
+
22
+
23
+if __name__ == "__main__":
24
+ main()
tests/watermarking/golden_candidates.py
new
+885
@@ -0,0 +1,885 @@
1
+# SPDX-License-Identifier: Apache-2.0
2
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
+
4
+"""Deterministic watermarking golden candidates."""
5
+
6
+import json
7
+import math
8
+from collections.abc import Mapping
9
+from dataclasses import dataclass, replace
10
+from pathlib import Path
11
+from typing import get_args
12
+
13
+import torch
14
+
15
+from vllm.config.watermarking import (
16
+ WatermarkConfig,
17
+ WatermarkContextScope,
18
+ WatermarkingAlgorithm,
19
+ WatermarkPRFName,
20
+ derive_watermark_key,
21
+)
22
+from vllm.v1.watermarking import (
23
+ DualKeyGumbelWatermarkDetector,
24
+ GumbelWatermarkDetector,
25
+ WatermarkDetection,
26
+ WatermarkDetector,
27
+ create_prf,
28
+ create_watermarker,
29
+)
30
+from vllm.v1.worker.gpu.sample.watermark import repeated_context_mask
31
+
32
+GOLDEN_SCHEMA_VERSION = 3
33
+
34
+# JSON floats round-trip exactly, but libm differs by an ULP across builds.
35
+GOLDEN_FLOAT_RTOL = 1e-9
36
+GOLDEN_FLOAT_ATOL = 1e-300
37
+
38
+P_VALUE_RATIO_MIN_DISTANCE = 1e-6
39
+REPETITIVE_MIN_KEY_PERTURBATION_TOKENS = 8
40
+REPETITIVE_MAX_P_VALUE_RATIO = 0.5
41
+ROUTING_BOUNDARY_MIN_DISTANCE = 1e-6
42
+
43
+WATERMARK_CONFIG_FIELDS = (
44
+ "algorithm",
45
+ "alpha",
46
+ "context_width",
47
+ "deduplicate_contexts",
48
+ "deduplicate_contexts_max_history",
49
+ "prf",
50
+ "allow_target_only_watermarking",
51
+)
52
+
53
+# round(((i + 1) * (5**0.5 - 1) / 2) % 1.0, 4) for i in range(64)
54
+ROUTING_UNIFORMS: tuple[float, ...] = (
55
+ 0.618, 0.2361, 0.8541, 0.4721, 0.0902, 0.7082, 0.3262, 0.9443,
56
+ 0.5623, 0.1803, 0.7984, 0.4164, 0.0344, 0.6525, 0.2705, 0.8885,
57
+ 0.5066, 0.1246, 0.7426, 0.3607, 0.9787, 0.5967, 0.2148, 0.8328,
58
+ 0.4508, 0.0689, 0.6869, 0.305, 0.923, 0.541, 0.1591, 0.7771,
59
+ 0.3951, 0.0132, 0.6312, 0.2492, 0.8673, 0.4853, 0.1033, 0.7214,
60
+ 0.3394, 0.9574, 0.5755, 0.1935, 0.8115, 0.4296, 0.0476, 0.6656,
61
+ 0.2837, 0.9017, 0.5197, 0.1378, 0.7558, 0.3738, 0.9919, 0.6099,
62
+ 0.2279, 0.846, 0.464, 0.082, 0.7001, 0.3181, 0.9361, 0.5542,
63
+) # fmt: skip
64
+
65
+
66
+class GoldenFormatError(ValueError):
67
+ """The stored goldens do not have the shape this module expects."""
68
+
69
+
70
+class GoldenGuardError(ValueError):
71
+ """A candidate is too weak or too unstable to be frozen as a golden."""
72
+
73
+
74
+@dataclass(frozen=True)
75
+class DeterministicGenerationFixture:
76
+ vocabulary_size: int = 128
77
+ num_tokens: int = 64
78
+ logit_denominator: int = 16
79
+ logit_modulus: int = 131
80
+ dominant_token: int | None = None
81
+ dominant_bias: int = 0
82
+ prompt: tuple[int, ...] = ()
83
+ routing_uniforms: tuple[float, ...] = ROUTING_UNIFORMS
84
+
85
+ def logits(self, position: int) -> torch.Tensor:
86
+ token_ids = torch.arange(self.vocabulary_size, dtype=torch.int64)
87
+ values = (token_ids * 37 + position * 17) % self.logit_modulus - 56
88
+ if self.dominant_token is not None:
89
+ values[self.dominant_token] += self.dominant_bias
90
+ return (values.to(torch.float32) / self.logit_denominator).unsqueeze(0)
91
+
92
+
93
+@dataclass(frozen=True)
94
+class WatermarkingSchemeConfig:
95
+ context_width: int = 4
96
+ generation_alpha: float = 0.1
97
+ detection_alpha: float = 0.1
98
+ generation_deduplicate_contexts: WatermarkContextScope = "single_turn"
99
+ generation_deduplicate_contexts_max_history: int | None = 8192
100
+ detection_deduplicate_contexts: bool = True
101
+ p_value_threshold: float = 0.01
102
+
103
+
104
+@dataclass(frozen=True)
105
+class GenerationTrace:
106
+ routing_draws: int
107
+ key_b_routed: int | None
108
+ key_b_effective: int | None
109
+ dedup_skips: int
110
+ partial_context_skips: int
111
+
112
+
113
+class _DeterministicSampler:
114
+ def __init__(self, routing_uniforms: tuple[float, ...]) -> None:
115
+ self.routing_uniforms = routing_uniforms
116
+ self.routing_position = 0
117
+ self.key_b_routed = 0
118
+
119
+ def __call__(self, logits: torch.Tensor) -> torch.Tensor:
120
+ if logits.shape[-1] != 2:
121
+ return logits.argmax(dim=-1)
122
+
123
+ probability_a = logits.softmax(dim=-1)[:, 0]
124
+ uniform = self.routing_uniforms[
125
+ self.routing_position % len(self.routing_uniforms)
126
+ ]
127
+ self.routing_position += 1
128
+ routed = (probability_a <= uniform).to(torch.int64)
129
+ self.key_b_routed += int(routed.sum())
130
+ return routed
131
+
132
+
133
+def routing_boundary(alpha: float) -> float:
134
+ """Return the realised key-A probability the deterministic sampler sees."""
135
+ logits = torch.tensor([1 - alpha, alpha], dtype=torch.float32).log()
136
+ return float(logits.softmax(dim=-1)[0])
137
+
138
+
139
+def _create_gumbel_detector(
140
+ key: int,
141
+ config: WatermarkingSchemeConfig,
142
+ prf: WatermarkPRFName,
143
+) -> WatermarkDetector:
144
+ return GumbelWatermarkDetector(
145
+ key=key,
146
+ context_width=config.context_width,
147
+ p_value_threshold=config.p_value_threshold,
148
+ prf=prf,
149
+ deduplicate_contexts=config.detection_deduplicate_contexts,
150
+ )
151
+
152
+
153
+def _create_dual_key_gumbel_detector(
154
+ key: int,
155
+ config: WatermarkingSchemeConfig,
156
+ prf: WatermarkPRFName,
157
+) -> WatermarkDetector:
158
+ return DualKeyGumbelWatermarkDetector(
159
+ key=key,
160
+ context_width=config.context_width,
161
+ p_value_threshold=config.p_value_threshold,
162
+ prf=prf,
163
+ deduplicate_contexts=config.detection_deduplicate_contexts,
164
+ alpha=config.detection_alpha,
165
+ )
166
+
167
+
168
+DETECTOR_FACTORIES = {
169
+ "gumbel": _create_gumbel_detector,
170
+ "dual_key_gumbel": _create_dual_key_gumbel_detector,
171
+}
172
+
173
+
174
+@dataclass(frozen=True)
175
+class WatermarkingCandidate:
176
+ id: str
177
+ scheme: WatermarkingAlgorithm
178
+ scheme_config: WatermarkingSchemeConfig
179
+ prf: WatermarkPRFName
180
+ key: int
181
+ detection_key: int
182
+ fixture: DeterministicGenerationFixture = DeterministicGenerationFixture()
183
+
184
+ def configuration(self) -> dict[str, object]:
185
+ prf_version = getattr(create_prf(self.prf, self.key), "version", None)
186
+ if not isinstance(prf_version, str):
187
+ raise ValueError(f"PRF {self.prf} does not define a version")
188
+ return {
189
+ "scheme": self.scheme,
190
+ "scheme_config": {
191
+ "context_width": self.scheme_config.context_width,
192
+ "generation_alpha": self.scheme_config.generation_alpha,
193
+ "detection_alpha": self.scheme_config.detection_alpha,
194
+ "generation_deduplicate_contexts": (
195
+ self.scheme_config.generation_deduplicate_contexts
196
+ ),
197
+ "generation_deduplicate_contexts_max_history": (
198
+ self.scheme_config.generation_deduplicate_contexts_max_history
199
+ ),
200
+ "detection_deduplicate_contexts": (
201
+ self.scheme_config.detection_deduplicate_contexts
202
+ ),
203
+ "p_value_threshold": self.scheme_config.p_value_threshold,
204
+ },
205
+ "prf": self.prf,
206
+ "prf_version": prf_version,
207
+ "key": str(self.key),
208
+ "detection_key": str(self.detection_key),
209
+ "fixture": {
210
+ "vocabulary_size": self.fixture.vocabulary_size,
211
+ "num_tokens": self.fixture.num_tokens,
212
+ "logit_denominator": self.fixture.logit_denominator,
213
+ "logit_modulus": self.fixture.logit_modulus,
214
+ "dominant_token": self.fixture.dominant_token,
215
+ "dominant_bias": self.fixture.dominant_bias,
216
+ "prompt": list(self.fixture.prompt),
217
+ },
218
+ }
219
+
220
+ def resolved(self) -> dict[str, object]:
221
+ """Return the vLLM-side state this candidate resolves to.
222
+
223
+ An allowlist rather than the whole dataclass, so a new production field
224
+ is a deliberate golden change: WATERMARK_CONFIG_FIELDS names the fields
225
+ recorded here and test_goldens.py checks it still covers
226
+ WatermarkConfig. Keys exceed 2**53 and are decimal strings.
227
+ """
228
+ config = self._watermark_config()
229
+ detector = self._detector()
230
+ key_b_prf = getattr(detector, "key_b_prf", None)
231
+ dual_key = self.scheme == "dual_key_gumbel"
232
+ return {
233
+ "watermark_config": {
234
+ field: getattr(config, field) for field in WATERMARK_CONFIG_FIELDS
235
+ },
236
+ "derived_keys": {
237
+ "key_a": str(derive_watermark_key(self.key, b"key_a"))
238
+ if dual_key
239
+ else None,
240
+ "key_b": str(derive_watermark_key(self.key, b"key_b"))
241
+ if dual_key
242
+ else None,
243
+ },
244
+ "detector": {
245
+ "type": type(detector).__name__,
246
+ "context_width": detector.context_width,
247
+ "p_value_threshold": detector.p_value_threshold,
248
+ "deduplicate_contexts": detector.deduplicate_contexts,
249
+ "alpha": getattr(detector, "alpha", None),
250
+ "prf_key": str(detector.prf.key),
251
+ "key_b_prf_key": None if key_b_prf is None else str(key_b_prf.key),
252
+ },
253
+ }
254
+
255
+ def generate(self) -> list[int]:
256
+ return self.generate_with_trace()[0]
257
+
258
+ def generate_with_trace(self) -> tuple[list[int], GenerationTrace]:
259
+ watermarker = create_watermarker(self._watermark_config())
260
+ sampler = _DeterministicSampler(self.fixture.routing_uniforms)
261
+ generated: list[int] = []
262
+ dedup_skips = 0
263
+ partial_context_skips = 0
264
+ key_b_effective = 0
265
+
266
+ for position in range(self.fixture.num_tokens):
267
+ context = self._context(generated)
268
+ skip_mask = self._skip_mask(generated, context)
269
+ skipped = skip_mask is not None and bool(skip_mask.item())
270
+ if skipped:
271
+ dedup_skips += 1
272
+ if len(generated) < self.scheme_config.context_width:
273
+ partial_context_skips += 1
274
+ routed_before = sampler.key_b_routed
275
+ sample = watermarker.sample(
276
+ self.fixture.logits(position),
277
+ context,
278
+ sampler,
279
+ skip_mask,
280
+ )
281
+ if sampler.key_b_routed > routed_before and not skipped:
282
+ key_b_effective += 1
283
+ generated.append(int(sample.token_ids.item()))
284
+
285
+ routes = self.scheme == "dual_key_gumbel" and (
286
+ 0 < self.scheme_config.generation_alpha < 1
287
+ )
288
+ trace = GenerationTrace(
289
+ routing_draws=sampler.routing_position,
290
+ key_b_routed=sampler.key_b_routed if routes else None,
291
+ key_b_effective=key_b_effective if routes else None,
292
+ dedup_skips=dedup_skips,
293
+ partial_context_skips=partial_context_skips,
294
+ )
295
+ return generated, trace
296
+
297
+ def detect(self, token_ids: list[int]) -> WatermarkDetection:
298
+ return self._detector().detect(token_ids)
299
+
300
+ def golden_entry(
301
+ self,
302
+ detection_token_ids: list[int] | None = None,
303
+ ) -> dict:
304
+ """Generate, detect and trace this candidate into one golden entry.
305
+
306
+ ``detection_token_ids`` runs detection over stored tokens instead of
307
+ the freshly generated ones, so a token drift and a detection drift are
308
+ reported independently.
309
+ """
310
+ token_ids, trace = self.generate_with_trace()
311
+ scored = token_ids if detection_token_ids is None else detection_token_ids
312
+ detection = self.detect(scored)
313
+ threshold = self.scheme_config.p_value_threshold
314
+ return {
315
+ "configuration": self.configuration(),
316
+ "resolved": self.resolved(),
317
+ "generation": token_ids,
318
+ "trace": _trace_payload(trace),
319
+ "detection": {
320
+ "score": detection.score,
321
+ "p_value": detection.p_value,
322
+ "p_value_ratio": detection.p_value / threshold,
323
+ "num_scored_tokens": detection.num_scored_tokens,
324
+ "is_watermarked": detection.is_watermarked,
325
+ },
326
+ }
327
+
328
+ def _watermark_config(self) -> WatermarkConfig:
329
+ return WatermarkConfig(
330
+ algorithm=self.scheme,
331
+ key=self.key,
332
+ alpha=self.scheme_config.generation_alpha,
333
+ context_width=self.scheme_config.context_width,
334
+ deduplicate_contexts=(self.scheme_config.generation_deduplicate_contexts),
335
+ deduplicate_contexts_max_history=(
336
+ self.scheme_config.generation_deduplicate_contexts_max_history
337
+ ),
338
+ prf=self.prf,
339
+ )
340
+
341
+ def _detector(self) -> WatermarkDetector:
342
+ return DETECTOR_FACTORIES[self.scheme](
343
+ self.detection_key,
344
+ self.scheme_config,
345
+ self.prf,
346
+ )
347
+
348
+ def _context(self, generated: list[int]) -> torch.Tensor:
349
+ width = self.scheme_config.context_width
350
+ padded = [-1] * width + generated
351
+ return torch.tensor([padded[-width:]], dtype=torch.int64)
352
+
353
+ def _skip_mask(
354
+ self, generated: list[int], context: torch.Tensor
355
+ ) -> torch.Tensor | None:
356
+ scope = self.scheme_config.generation_deduplicate_contexts
357
+ if scope == "none":
358
+ return None
359
+
360
+ prompt_len = len(self.fixture.prompt)
361
+ storage = torch.zeros(
362
+ (1, prompt_len + self.fixture.num_tokens),
363
+ dtype=torch.int64,
364
+ )
365
+ if prompt_len:
366
+ storage[0, :prompt_len] = torch.tensor(self.fixture.prompt)
367
+ if generated:
368
+ storage[0, prompt_len : prompt_len + len(generated)] = torch.tensor(
369
+ generated
370
+ )
371
+ return repeated_context_mask(
372
+ storage,
373
+ torch.tensor([0]),
374
+ torch.tensor([prompt_len]),
375
+ torch.tensor([prompt_len + len(generated)]),
376
+ context,
377
+ self.scheme_config.generation_deduplicate_contexts_max_history,
378
+ include_prompt=scope == "all",
379
+ skip_partial_context=scope == "all",
380
+ )
381
+
382
+
383
+def _trace_payload(trace: GenerationTrace) -> dict:
384
+ return {
385
+ "routing_draws": trace.routing_draws,
386
+ "key_b_routed": trace.key_b_routed,
387
+ "key_b_effective": trace.key_b_effective,
388
+ "dedup_skips": trace.dedup_skips,
389
+ "partial_context_skips": trace.partial_context_skips,
390
+ }
391
+
392
+
393
+BALANCED_FIXTURE = DeterministicGenerationFixture()
394
+
395
+# The first five tokens of BALANCED_FIXTURE under scope "all", so position 4 repeats.
396
+PROMPT_FIXTURE = DeterministicGenerationFixture(prompt=(46, 42, 38, 34, 122))
397
+
398
+REPETITIVE_FIXTURE = DeterministicGenerationFixture(
399
+ vocabulary_size=16,
400
+ num_tokens=48,
401
+ dominant_token=3,
402
+ dominant_bias=52,
403
+)
404
+
405
+MIDDLE_FIXTURE = DeterministicGenerationFixture(
406
+ vocabulary_size=8,
407
+ num_tokens=64,
408
+ dominant_token=3,
409
+ dominant_bias=16,
410
+)
411
+
412
+# Few enough scored tokens that the p_value lands just under its threshold.
413
+NEAR_THRESHOLD_FIXTURE = DeterministicGenerationFixture(
414
+ vocabulary_size=16,
415
+ num_tokens=8,
416
+)
417
+
418
+
419
+def _candidate(
420
+ id: str,
421
+ scheme: WatermarkingAlgorithm,
422
+ key: int,
423
+ *,
424
+ prf: WatermarkPRFName,
425
+ detection_key: int | None = None,
426
+ context_width: int = 4,
427
+ generation_alpha: float = 0.1,
428
+ detection_alpha: float | None = None,
429
+ generation_deduplicate_contexts: WatermarkContextScope = "single_turn",
430
+ generation_deduplicate_contexts_max_history: int | None = 8192,
431
+ detection_deduplicate_contexts: bool = True,
432
+ p_value_threshold: float = 0.01,
433
+ fixture: DeterministicGenerationFixture = BALANCED_FIXTURE,
434
+) -> WatermarkingCandidate:
435
+ return WatermarkingCandidate(
436
+ id=id,
437
+ scheme=scheme,
438
+ scheme_config=WatermarkingSchemeConfig(
439
+ context_width=context_width,
440
+ generation_alpha=generation_alpha,
441
+ detection_alpha=(
442
+ generation_alpha if detection_alpha is None else detection_alpha
443
+ ),
444
+ generation_deduplicate_contexts=generation_deduplicate_contexts,
445
+ generation_deduplicate_contexts_max_history=(
446
+ generation_deduplicate_contexts_max_history
447
+ ),
448
+ detection_deduplicate_contexts=detection_deduplicate_contexts,
449
+ p_value_threshold=p_value_threshold,
450
+ ),
451
+ prf=prf,
452
+ key=key,
453
+ detection_key=key if detection_key is None else detection_key,
454
+ fixture=fixture,
455
+ )
456
+
457
+
458
+WATERMARKING_CANDIDATES = (
459
+ _candidate("gumbel-philox-key0-cw1", "gumbel", 0, prf="philox", context_width=1),
460
+ _candidate("gumbel-philox-key42-cw4", "gumbel", 42, prf="philox"),
461
+ _candidate(
462
+ "gumbel-philox-key42-cw4-wrong-key",
463
+ "gumbel",
464
+ 42,
465
+ prf="philox",
466
+ detection_key=43,
467
+ ),
468
+ _candidate(
469
+ "gumbel-philox-key2p32-cw5-no-dedup",
470
+ "gumbel",
471
+ 2**32,
472
+ prf="philox",
473
+ context_width=5,
474
+ generation_deduplicate_contexts="none",
475
+ detection_deduplicate_contexts=False,
476
+ ),
477
+ _candidate(
478
+ "gumbel-philox-keymax-cw16-all",
479
+ "gumbel",
480
+ 2**64 - 1,
481
+ prf="philox",
482
+ context_width=16,
483
+ generation_deduplicate_contexts="all",
484
+ ),
485
+ _candidate(
486
+ "gumbel-philox-key42-cw4-all",
487
+ "gumbel",
488
+ 42,
489
+ prf="philox",
490
+ generation_deduplicate_contexts="all",
491
+ ),
492
+ _candidate(
493
+ "gumbel-philox-key42-cw4-all-prompt",
494
+ "gumbel",
495
+ 42,
496
+ prf="philox",
497
+ generation_deduplicate_contexts="all",
498
+ fixture=PROMPT_FIXTURE,
499
+ ),
500
+ _candidate(
501
+ "gumbel-philox-key42-cw4-mid-history8",
502
+ "gumbel",
503
+ 42,
504
+ prf="philox",
505
+ generation_deduplicate_contexts_max_history=8,
506
+ fixture=MIDDLE_FIXTURE,
507
+ ),
508
+ _candidate(
509
+ "gumbel-philox-key42-cw4-mid-history-none",
510
+ "gumbel",
511
+ 42,
512
+ prf="philox",
513
+ generation_deduplicate_contexts_max_history=None,
514
+ fixture=MIDDLE_FIXTURE,
515
+ ),
516
+ _candidate(
517
+ "gumbel-philox-key42-cw4-mid-no-dedup",
518
+ "gumbel",
519
+ 42,
520
+ prf="philox",
521
+ generation_deduplicate_contexts="none",
522
+ generation_deduplicate_contexts_max_history=None,
523
+ detection_deduplicate_contexts=False,
524
+ fixture=MIDDLE_FIXTURE,
525
+ ),
526
+ _candidate(
527
+ "gumbel-philox-key42-cw4-mid-all",
528
+ "gumbel",
529
+ 42,
530
+ prf="philox",
531
+ generation_deduplicate_contexts="all",
532
+ generation_deduplicate_contexts_max_history=None,
533
+ fixture=MIDDLE_FIXTURE,
534
+ ),
535
+ _candidate(
536
+ "gumbel-philox-key42-cw4-near-threshold",
537
+ "gumbel",
538
+ 42,
539
+ prf="philox",
540
+ p_value_threshold=0.0015,
541
+ fixture=NEAR_THRESHOLD_FIXTURE,
542
+ ),
543
+ _candidate(
544
+ "gumbel-philox-repeated-cw1",
545
+ "gumbel",
546
+ 42,
547
+ prf="philox",
548
+ context_width=1,
549
+ fixture=REPETITIVE_FIXTURE,
550
+ ),
551
+ _candidate(
552
+ "gumbel-philox-repeated-cw4-all",
553
+ "gumbel",
554
+ 42,
555
+ prf="philox",
556
+ generation_deduplicate_contexts="all",
557
+ fixture=REPETITIVE_FIXTURE,
558
+ ),
559
+ _candidate(
560
+ "dual-key-gumbel-philox-key0-cw1-alpha0",
561
+ "dual_key_gumbel",
562
+ 0,
563
+ prf="philox",
564
+ context_width=1,
565
+ generation_alpha=0.0,
566
+ ),
567
+ _candidate(
568
+ "dual-key-gumbel-philox-key0-cw4-alpha0.1",
569
+ "dual_key_gumbel",
570
+ 0,
571
+ prf="philox",
572
+ ),
573
+ _candidate(
574
+ "dual-key-gumbel-philox-key42-cw4-alpha-mismatch",
575
+ "dual_key_gumbel",
576
+ 42,
577
+ prf="philox",
578
+ generation_alpha=0.1,
579
+ detection_alpha=0.2,
580
+ ),
581
+ _candidate(
582
+ "dual-key-gumbel-philox-key2p32-cw5-alpha0.5",
583
+ "dual_key_gumbel",
584
+ 2**32,
585
+ prf="philox",
586
+ context_width=5,
587
+ generation_alpha=0.5,
588
+ ),
589
+ _candidate(
590
+ "dual-key-gumbel-philox-keymax-cw16-alpha1",
591
+ "dual_key_gumbel",
592
+ 2**64 - 1,
593
+ prf="philox",
594
+ context_width=16,
595
+ generation_alpha=1.0,
596
+ ),
597
+ _candidate(
598
+ "dual-key-gumbel-philox-keymax-cw4-alpha0.4",
599
+ "dual_key_gumbel",
600
+ 2**64 - 1,
601
+ prf="philox",
602
+ generation_alpha=0.4,
603
+ ),
604
+ _candidate(
605
+ "dual-key-gumbel-philox-key7-cw4-near-threshold",
606
+ "dual_key_gumbel",
607
+ 7,
608
+ prf="philox",
609
+ p_value_threshold=0.003,
610
+ fixture=NEAR_THRESHOLD_FIXTURE,
611
+ ),
612
+ _candidate(
613
+ "dual-key-gumbel-philox-repeated-cw1",
614
+ "dual_key_gumbel",
615
+ 42,
616
+ prf="philox",
617
+ context_width=1,
618
+ fixture=REPETITIVE_FIXTURE,
619
+ ),
620
+ _candidate(
621
+ "dual-key-gumbel-philox-repeated-cw4-all",
622
+ "dual_key_gumbel",
623
+ 42,
624
+ prf="philox",
625
+ generation_deduplicate_contexts="all",
626
+ fixture=REPETITIVE_FIXTURE,
627
+ ),
628
+)
629
+
630
+DEDUPLICATION_TWINS = (
631
+ (
632
+ "gumbel-philox-key42-cw4-mid-history-none",
633
+ "gumbel-philox-key42-cw4-mid-no-dedup",
634
+ ),
635
+)
636
+
637
+
638
+def validate_golden_guards(entries: Mapping[str, dict]) -> None:
639
+ candidates_by_id = {
640
+ candidate.id: candidate for candidate in WATERMARKING_CANDIDATES
641
+ }
642
+ combinations = {
643
+ (candidate.scheme, candidate.prf) for candidate in WATERMARKING_CANDIDATES
644
+ }
645
+ expected_combinations = configured_algorithm_prf_combinations()
646
+ if combinations != expected_combinations:
647
+ missing_combinations = sorted(expected_combinations - combinations)
648
+ unexpected_combinations = sorted(combinations - expected_combinations)
649
+ raise GoldenGuardError(
650
+ "candidate scheme/PRF coverage mismatch: "
651
+ f"missing {missing_combinations}, unexpected {unexpected_combinations}"
652
+ )
653
+
654
+ missing = sorted(set(candidates_by_id) - set(entries))
655
+ if missing:
656
+ raise GoldenGuardError(f"golden entries are missing candidates: {missing}")
657
+
658
+ for candidate in WATERMARKING_CANDIDATES:
659
+ entry = entries[candidate.id]
660
+ ratio = entry["detection"]["p_value_ratio"]
661
+ if abs(ratio - 1.0) < P_VALUE_RATIO_MIN_DISTANCE:
662
+ raise GoldenGuardError(
663
+ f"{candidate.id}: p_value is within "
664
+ f"{P_VALUE_RATIO_MIN_DISTANCE:g} of p_value_threshold "
665
+ f"(ratio {ratio!r}), so is_watermarked is not reproducible"
666
+ )
667
+
668
+ if candidate.fixture == REPETITIVE_FIXTURE:
669
+ alternate_tokens = replace(candidate, key=candidate.key ^ 1).generate()
670
+ changed_tokens = sum(
671
+ actual != alternate
672
+ for actual, alternate in zip(
673
+ entry["generation"], alternate_tokens, strict=True
674
+ )
675
+ )
676
+ if changed_tokens < REPETITIVE_MIN_KEY_PERTURBATION_TOKENS:
677
+ raise GoldenGuardError(
678
+ f"{candidate.id}: key ^ 1 changes only {changed_tokens} tokens; "
679
+ f"expected at least {REPETITIVE_MIN_KEY_PERTURBATION_TOKENS}"
680
+ )
681
+ full_context_skips = (
682
+ entry["trace"]["dedup_skips"] - entry["trace"]["partial_context_skips"]
683
+ )
684
+ if full_context_skips < 1:
685
+ raise GoldenGuardError(
686
+ f"{candidate.id}: repetitive fixture has no full-context "
687
+ "deduplication skip"
688
+ )
689
+ if ratio > REPETITIVE_MAX_P_VALUE_RATIO:
690
+ raise GoldenGuardError(
691
+ f"{candidate.id}: p_value_ratio {ratio!r} exceeds "
692
+ f"{REPETITIVE_MAX_P_VALUE_RATIO}"
693
+ )
694
+
695
+ alpha = candidate.scheme_config.generation_alpha
696
+ if candidate.scheme == "dual_key_gumbel" and 0 < alpha < 1:
697
+ boundary = routing_boundary(alpha)
698
+ distance = min(
699
+ abs(uniform - boundary)
700
+ for uniform in candidate.fixture.routing_uniforms
701
+ )
702
+ if distance < ROUTING_BOUNDARY_MIN_DISTANCE:
703
+ raise GoldenGuardError(
704
+ f"{candidate.id}: routing uniform is only {distance!r} from "
705
+ f"the realised boundary; expected at least "
706
+ f"{ROUTING_BOUNDARY_MIN_DISTANCE:g}"
707
+ )
708
+
709
+ for enabled_id, disabled_id in DEDUPLICATION_TWINS:
710
+ enabled = candidates_by_id[enabled_id]
711
+ disabled = candidates_by_id[disabled_id]
712
+ expected_disabled = replace(
713
+ enabled,
714
+ id=disabled_id,
715
+ scheme_config=replace(
716
+ enabled.scheme_config,
717
+ generation_deduplicate_contexts="none",
718
+ detection_deduplicate_contexts=False,
719
+ ),
720
+ )
721
+ if disabled != expected_disabled:
722
+ raise GoldenGuardError(
723
+ f"{enabled_id} and {disabled_id} must differ only in generation "
724
+ "and detection deduplication"
725
+ )
726
+
727
+ enabled_entry = entries[enabled_id]
728
+ disabled_entry = entries[disabled_id]
729
+ if enabled_entry["trace"]["dedup_skips"] < 1:
730
+ raise GoldenGuardError(f"{enabled_id}: expected at least one dedup skip")
731
+ if disabled_entry["trace"]["dedup_skips"] != 0:
732
+ raise GoldenGuardError(f"{disabled_id}: expected zero dedup skips")
733
+ if enabled_entry["generation"] == disabled_entry["generation"]:
734
+ raise GoldenGuardError(
735
+ f"{enabled_id} and {disabled_id}: generations must differ"
736
+ )
737
+ enabled_scored = enabled_entry["detection"]["num_scored_tokens"]
738
+ disabled_scored = disabled_entry["detection"]["num_scored_tokens"]
739
+ if enabled_scored == disabled_scored:
740
+ raise GoldenGuardError(
741
+ f"{enabled_id} and {disabled_id}: detector scored-token counts "
742
+ "must differ"
743
+ )
744
+
745
+
746
+def golden_payload() -> dict:
747
+ candidates = {
748
+ candidate.id: candidate.golden_entry() for candidate in WATERMARKING_CANDIDATES
749
+ }
750
+ return {
751
+ "schema_version": GOLDEN_SCHEMA_VERSION,
752
+ "candidates": candidates,
753
+ }
754
+
755
+
756
+def floats_match(actual: float, expected: float) -> bool:
757
+ return math.isclose(
758
+ actual,
759
+ expected,
760
+ rel_tol=GOLDEN_FLOAT_RTOL,
761
+ abs_tol=GOLDEN_FLOAT_ATOL,
762
+ )
763
+
764
+
765
+def _relative_difference(actual: float, expected: float) -> float:
766
+ if expected == 0.0:
767
+ return 0.0 if actual == 0.0 else math.inf
768
+ return abs(actual - expected) / abs(expected)
769
+
770
+
771
+def _compare_float(
772
+ field: str,
773
+ actual: float,
774
+ expected: float,
775
+ differences: list[str],
776
+) -> None:
777
+ if not floats_match(actual, expected):
778
+ differences.append(
779
+ f"{field}: expected {expected!r}, got {actual!r}, "
780
+ f"relative difference {_relative_difference(actual, expected):.3e}"
781
+ )
782
+
783
+
784
+def _compare_exact(
785
+ field: str,
786
+ actual: object,
787
+ expected: object,
788
+ differences: list[str],
789
+) -> None:
790
+ if actual != expected:
791
+ differences.append(f"{field}: expected {expected!r}, got {actual!r}")
792
+
793
+
794
+def _compare_mapping(
795
+ field: str,
796
+ actual: Mapping[str, object],
797
+ expected: Mapping[str, object],
798
+ differences: list[str],
799
+) -> None:
800
+ for key in sorted(set(actual) | set(expected)):
801
+ if actual.get(key) != expected.get(key):
802
+ differences.append(
803
+ f"{field}.{key}: expected {expected.get(key)!r}, "
804
+ f"got {actual.get(key)!r}"
805
+ )
806
+
807
+
808
+def compare_entries(produced: dict, golden: dict) -> list[str]:
809
+ """Return one line per field that differs, empty when the two agree.
810
+
811
+ Configuration, resolved state, tokens, trace,
812
+ num_scored_tokens and is_watermarked are compared exactly; score, p_value
813
+ and p_value_ratio are compared with GOLDEN_FLOAT_RTOL.
814
+ """
815
+ differences: list[str] = []
816
+ for field in ("configuration", "resolved", "trace"):
817
+ _compare_mapping(field, produced[field], golden[field], differences)
818
+
819
+ if produced["generation"] != golden["generation"]:
820
+ first_difference = next(
821
+ (
822
+ index
823
+ for index, (actual, expected) in enumerate(
824
+ zip(produced["generation"], golden["generation"])
825
+ )
826
+ if actual != expected
827
+ ),
828
+ min(len(produced["generation"]), len(golden["generation"])),
829
+ )
830
+ differences.append(
831
+ f"generation: first differs at index {first_difference} "
832
+ f"({len(produced['generation'])} tokens generated, "
833
+ f"{len(golden['generation'])} in the golden): "
834
+ f"expected {golden['generation']}, got {produced['generation']}"
835
+ )
836
+
837
+ detection = produced["detection"]
838
+ expected_detection = golden["detection"]
839
+ for field in ("score", "p_value", "p_value_ratio"):
840
+ _compare_float(
841
+ f"detection.{field}",
842
+ detection[field],
843
+ expected_detection[field],
844
+ differences,
845
+ )
846
+ for field in ("num_scored_tokens", "is_watermarked"):
847
+ _compare_exact(
848
+ f"detection.{field}",
849
+ detection[field],
850
+ expected_detection[field],
851
+ differences,
852
+ )
853
+ return differences
854
+
855
+
856
+def compare_golden(candidate: WatermarkingCandidate, golden: dict) -> list[str]:
857
+ """Return one line per field of ``candidate`` that drifted from ``golden``."""
858
+ return compare_entries(candidate.golden_entry(golden["generation"]), golden)
859
+
860
+
861
+def read_goldens(path: Path) -> dict[str, dict]:
862
+ """Read the goldens file and return its candidate mapping."""
863
+ payload = json.loads(path.read_text(encoding="utf-8"))
864
+ version = payload.get("schema_version")
865
+ if version != GOLDEN_SCHEMA_VERSION:
866
+ raise GoldenFormatError(
867
+ f"{path}: schema_version {version!r}, expected {GOLDEN_SCHEMA_VERSION}"
868
+ )
869
+ return payload["candidates"]
870
+
871
+
872
+def configured_algorithms() -> set[str]:
873
+ return set(get_args(WatermarkingAlgorithm))
874
+
875
+
876
+def configured_prfs() -> set[str]:
877
+ return set(get_args(WatermarkPRFName))
878
+
879
+
880
+def configured_algorithm_prf_combinations() -> set[tuple[str, str]]:
881
+ return {
882
+ (algorithm, prf)
883
+ for algorithm in configured_algorithms()
884
+ for prf in configured_prfs()
885
+ }
tests/watermarking/test_goldens.py
new
+99
@@ -0,0 +1,99 @@
1
+# SPDX-License-Identifier: Apache-2.0
2
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
+
4
+"""Check the watermarking goldens still reproduce."""
5
+
6
+import dataclasses
7
+from pathlib import Path
8
+
9
+import pytest
10
+
11
+from tests.watermarking.golden_candidates import (
12
+ DETECTOR_FACTORIES,
13
+ GOLDEN_FLOAT_RTOL,
14
+ WATERMARK_CONFIG_FIELDS,
15
+ WATERMARKING_CANDIDATES,
16
+ compare_golden,
17
+ configured_algorithm_prf_combinations,
18
+ configured_algorithms,
19
+ read_goldens,
20
+ routing_boundary,
21
+ validate_golden_guards,
22
+)
23
+from vllm.config.watermarking import WatermarkConfig
24
+
25
+GOLDENS_PATH = Path(__file__).with_name("watermarking_goldens.json")
26
+
27
+CANDIDATES_BY_ID = {candidate.id: candidate for candidate in WATERMARKING_CANDIDATES}
28
+
29
+NEGATIVE_CANDIDATE_ID = "gumbel-philox-key42-cw4-wrong-key"
30
+
31
+
32
+@pytest.fixture(scope="module")
33
+def goldens() -> dict[str, dict]:
34
+ return read_goldens(GOLDENS_PATH)
35
+
36
+
37
+def test_goldens_cover_every_candidate(goldens: dict[str, dict]):
38
+ candidate_ids = set(CANDIDATES_BY_ID)
39
+
40
+ assert len(candidate_ids) == len(WATERMARKING_CANDIDATES)
41
+ assert set(goldens) == candidate_ids, "golden contract does not match candidates"
42
+ candidate_combinations = {
43
+ (candidate.scheme, candidate.prf) for candidate in WATERMARKING_CANDIDATES
44
+ }
45
+ assert candidate_combinations == configured_algorithm_prf_combinations()
46
+ assert set(DETECTOR_FACTORIES) == configured_algorithms()
47
+
48
+
49
+def test_golden_fixture_guards(goldens: dict[str, dict]):
50
+ validate_golden_guards(goldens)
51
+
52
+
53
+def test_resolved_records_every_watermark_config_field():
54
+ assert {field.name for field in dataclasses.fields(WatermarkConfig)} == (
55
+ set(WATERMARK_CONFIG_FIELDS) | {"key"}
56
+ )
57
+
58
+
59
+@pytest.mark.parametrize(
60
+ "candidate",
61
+ WATERMARKING_CANDIDATES,
62
+ ids=lambda candidate: candidate.id,
63
+)
64
+def test_watermarking_candidate_golden(candidate, goldens: dict[str, dict]):
65
+ differences = compare_golden(candidate, goldens[candidate.id])
66
+
67
+ assert not differences, "\n".join(
68
+ [
69
+ f"{candidate.id}: golden drift "
70
+ f"(tolerance {GOLDEN_FLOAT_RTOL:g} on score and p_value)",
71
+ *differences,
72
+ ]
73
+ )
74
+
75
+
76
+def test_negative_row_is_not_watermarked(goldens: dict[str, dict]):
77
+ candidate = CANDIDATES_BY_ID[NEGATIVE_CANDIDATE_ID]
78
+
79
+ assert candidate.detection_key != candidate.key
80
+ assert goldens[NEGATIVE_CANDIDATE_ID]["detection"]["is_watermarked"] is False
81
+
82
+
83
+@pytest.mark.parametrize(
84
+ "candidate",
85
+ [
86
+ candidate
87
+ for candidate in WATERMARKING_CANDIDATES
88
+ if candidate.scheme == "dual_key_gumbel"
89
+ and 0 < candidate.scheme_config.generation_alpha < 1
90
+ ],
91
+ ids=lambda candidate: candidate.id,
92
+)
93
+def test_routing_sequence_resolves_alpha(candidate):
94
+ alpha = candidate.scheme_config.generation_alpha
95
+ uniforms = candidate.fixture.routing_uniforms
96
+ boundary = routing_boundary(alpha)
97
+ share = sum(1 for uniform in uniforms if boundary <= uniform) / len(uniforms)
98
+
99
+ assert abs(share - alpha) <= 0.03
tests/watermarking/test_watermarking.py
+6
-3
@@ -276,9 +276,9 @@ def test_gpu_sampler_warns_when_watermarking_is_enabled_for_greedy(monkeypatch):
276
"vllm.v1.watermarking.gpu_sampler.logger.warning_once", messages.append
277
)
278
279
- sampler.add_request(0, 1, SamplingParams(temperature=0))
280
- sampler.add_request(0, 1, SamplingParams(temperature=1))
281
- sampler.add_request(0, 1, SamplingParams(temperature=0, watermarking=False))
279
+ sampler.add_request(0, SamplingParams(temperature=0))
280
+ sampler.add_request(0, SamplingParams(temperature=1))
281
+ sampler.add_request(0, SamplingParams(temperature=0, watermarking=False))
282
283
assert messages == [
284
(
@@ -945,6 +945,7 @@ def test_draft_sampler_uses_draft_key_and_advances_context(monkeypatch):
945
speculator = object.__new__(StubSpeculator)
946
speculator.model = StubModel()
947
speculator.use_fp64_gumbel = False
948
+ speculator.acceptance_estimator = None
949
draft_watermarker = object.__new__(DraftWatermarker)
950
draft_watermarker.watermarker = StubWatermarker()
951
draft_watermarker.contexts = torch.tensor([[1, 2], [3, 4]])
@@ -978,6 +979,7 @@ def test_dspark_reduced_vocab_draft_sampler_applies_watermarking(monkeypatch):
979
speculator.seeds = torch.zeros(2, dtype=torch.int64)
980
speculator._step_cols = torch.tensor([0])
981
speculator.use_fp64_gumbel = False
982
+ speculator.acceptance_estimator = None
983
watermark_logits: list[torch.Tensor] = []
984
985
def sample(logits, sampled, idx_map, temperature):
@@ -1012,6 +1014,7 @@ def test_dspark_target_only_watermarking_leaves_drafts_unwatermarked(monkeypatch
1014
speculator.seeds = torch.zeros(2, dtype=torch.int64)
1015
speculator._step_cols = torch.tensor([0])
1016
speculator.use_fp64_gumbel = False
1017
+ speculator.acceptance_estimator = None
1018
speculator.draft_watermarker = None
1019
monkeypatch.setattr(
1020
"vllm.v1.worker.gpu.spec_decode.dspark.speculator.gumbel_sample",
tests/watermarking/watermarking_goldens.json
new
+2848
@@ -0,0 +1,2848 @@
1
+{
2
+ "candidates": {
3
+ "dual-key-gumbel-philox-key0-cw1-alpha0": {
4
+ "configuration": {
5
+ "detection_key": "0",
6
+ "fixture": {
7
+ "dominant_bias": 0,
8
+ "dominant_token": null,
9
+ "logit_denominator": 16,
10
+ "logit_modulus": 131,
11
+ "num_tokens": 64,
12
+ "prompt": [],
13
+ "vocabulary_size": 128
14
+ },
15
+ "key": "0",
16
+ "prf": "philox",
17
+ "prf_version": "philox4x32-10-v1",
18
+ "scheme": "dual_key_gumbel",
19
+ "scheme_config": {
20
+ "context_width": 1,
21
+ "detection_alpha": 0.0,
22
+ "detection_deduplicate_contexts": true,
23
+ "generation_alpha": 0.0,
24
+ "generation_deduplicate_contexts": "single_turn",
25
+ "generation_deduplicate_contexts_max_history": 8192,
26
+ "p_value_threshold": 0.01
27
+ }
28
+ },
29
+ "detection": {
30
+ "is_watermarked": true,
31
+ "num_scored_tokens": 55,
32
+ "p_value": 2.7410983620034455e-44,
33
+ "p_value_ratio": 2.7410983620034455e-42,
34
+ "score": 229.87923167230588
35
+ },
36
+ "generation": [
37
+ 81,
38
+ 91,
39
+ 84,
40
+ 122,
41
+ 37,
42
+ 118,
43
+ 11,
44
+ 3,
45
+ 116,
46
+ 56,
47
+ 66,
48
+ 37,
49
+ 44,
50
+ 40,
51
+ 85,
52
+ 31,
53
+ 102,
54
+ 73,
55
+ 126,
56
+ 16,
57
+ 40,
58
+ 93,
59
+ 11,
60
+ 85,
61
+ 81,
62
+ 77,
63
+ 41,
64
+ 12,
65
+ 118,
66
+ 61,
67
+ 57,
68
+ 53,
69
+ 38,
70
+ 111,
71
+ 115,
72
+ 5,
73
+ 1,
74
+ 99,
75
+ 113,
76
+ 28,
77
+ 87,
78
+ 55,
79
+ 83,
80
+ 51,
81
+ 47,
82
+ 57,
83
+ 124,
84
+ 31,
85
+ 116,
86
+ 112,
87
+ 30,
88
+ 43,
89
+ 89,
90
+ 110,
91
+ 60,
92
+ 10,
93
+ 9,
94
+ 58,
95
+ 114,
96
+ 125,
97
+ 68,
98
+ 78,
99
+ 106,
100
+ 56
101
+ ],
102
+ "resolved": {
103
+ "derived_keys": {
104
+ "key_a": "15691511769010696906",
105
+ "key_b": "9736202488081271922"
106
+ },
107
+ "detector": {
108
+ "alpha": 0.0,
109
+ "context_width": 1,
110
+ "deduplicate_contexts": true,
111
+ "key_b_prf_key": "9736202488081271922",
112
+ "p_value_threshold": 0.01,
113
+ "prf_key": "15691511769010696906",
114
+ "type": "DualKeyGumbelWatermarkDetector"
115
+ },
116
+ "watermark_config": {
117
+ "algorithm": "dual_key_gumbel",
118
+ "allow_target_only_watermarking": false,
119
+ "alpha": 0.0,
120
+ "context_width": 1,
121
+ "deduplicate_contexts": "single_turn",
122
+ "deduplicate_contexts_max_history": 8192,
123
+ "prf": "philox"
124
+ }
125
+ },
126
+ "trace": {
127
+ "dedup_skips": 9,
128
+ "key_b_effective": null,
129
+ "key_b_routed": null,
130
+ "partial_context_skips": 0,
131
+ "routing_draws": 0
132
+ }
133
+ },
134
+ "dual-key-gumbel-philox-key0-cw4-alpha0.1": {
135
+ "configuration": {
136
+ "detection_key": "0",
137
+ "fixture": {
138
+ "dominant_bias": 0,
139
+ "dominant_token": null,
140
+ "logit_denominator": 16,
141
+ "logit_modulus": 131,
142
+ "num_tokens": 64,
143
+ "prompt": [],
144
+ "vocabulary_size": 128
145
+ },
146
+ "key": "0",
147
+ "prf": "philox",
148
+ "prf_version": "philox4x32-10-v1",
149
+ "scheme": "dual_key_gumbel",
150
+ "scheme_config": {
151
+ "context_width": 4,
152
+ "detection_alpha": 0.1,
153
+ "detection_deduplicate_contexts": true,
154
+ "generation_alpha": 0.1,
155
+ "generation_deduplicate_contexts": "single_turn",
156
+ "generation_deduplicate_contexts_max_history": 8192,
157
+ "p_value_threshold": 0.01
158
+ }
159
+ },
160
+ "detection": {
161
+ "is_watermarked": true,
162
+ "num_scored_tokens": 64,
163
+ "p_value": 1.234132682420224e-51,
164
+ "p_value_ratio": 1.234132682420224e-49,
165
+ "score": 241.81126265648692
166
+ },
167
+ "generation": [
168
+ 70,
169
+ 56,
170
+ 91,
171
+ 90,
172
+ 72,
173
+ 68,
174
+ 17,
175
+ 78,
176
+ 21,
177
+ 116,
178
+ 104,
179
+ 62,
180
+ 15,
181
+ 100,
182
+ 82,
183
+ 13,
184
+ 88,
185
+ 70,
186
+ 112,
187
+ 62,
188
+ 79,
189
+ 57,
190
+ 11,
191
+ 113,
192
+ 88,
193
+ 80,
194
+ 23,
195
+ 90,
196
+ 79,
197
+ 42,
198
+ 18,
199
+ 60,
200
+ 10,
201
+ 73,
202
+ 94,
203
+ 64,
204
+ 96,
205
+ 71,
206
+ 35,
207
+ 56,
208
+ 38,
209
+ 93,
210
+ 37,
211
+ 54,
212
+ 82,
213
+ 127,
214
+ 0,
215
+ 45,
216
+ 37,
217
+ 75,
218
+ 19,
219
+ 92,
220
+ 68,
221
+ 127,
222
+ 28,
223
+ 56,
224
+ 45,
225
+ 69,
226
+ 8,
227
+ 1,
228
+ 110,
229
+ 39,
230
+ 127,
231
+ 56
232
+ ],
233
+ "resolved": {
234
+ "derived_keys": {
235
+ "key_a": "15691511769010696906",
236
+ "key_b": "9736202488081271922"
237
+ },
238
+ "detector": {
239
+ "alpha": 0.1,
240
+ "context_width": 4,
241
+ "deduplicate_contexts": true,
242
+ "key_b_prf_key": "9736202488081271922",
243
+ "p_value_threshold": 0.01,
244
+ "prf_key": "15691511769010696906",
245
+ "type": "DualKeyGumbelWatermarkDetector"
246
+ },
247
+ "watermark_config": {
248
+ "algorithm": "dual_key_gumbel",
249
+ "allow_target_only_watermarking": false,
250
+ "alpha": 0.1,
251
+ "context_width": 4,
252
+ "deduplicate_contexts": "single_turn",
253
+ "deduplicate_contexts_max_history": 8192,
254
+ "prf": "philox"
255
+ }
256
+ },
257
+ "trace": {
258
+ "dedup_skips": 0,
259
+ "key_b_effective": 7,
260
+ "key_b_routed": 7,
261
+ "partial_context_skips": 0,
262
+ "routing_draws": 64
263
+ }
264
+ },
265
+ "dual-key-gumbel-philox-key2p32-cw5-alpha0.5": {
266
+ "configuration": {
267
+ "detection_key": "4294967296",
268
+ "fixture": {
269
+ "dominant_bias": 0,
270
+ "dominant_token": null,
271
+ "logit_denominator": 16,
272
+ "logit_modulus": 131,
273
+ "num_tokens": 64,
274
+ "prompt": [],
275
+ "vocabulary_size": 128
276
+ },
277
+ "key": "4294967296",
278
+ "prf": "philox",
279
+ "prf_version": "philox4x32-10-v1",
280
+ "scheme": "dual_key_gumbel",
281
+ "scheme_config": {
282
+ "context_width": 5,
283
+ "detection_alpha": 0.5,
284
+ "detection_deduplicate_contexts": true,
285
+ "generation_alpha": 0.5,
286
+ "generation_deduplicate_contexts": "single_turn",
287
+ "generation_deduplicate_contexts_max_history": 8192,
288
+ "p_value_threshold": 0.01
289
+ }
290
+ },
291
+ "detection": {
292
+ "is_watermarked": true,
293
+ "num_scored_tokens": 64,
294
+ "p_value": 6.733621085489817e-36,
295
+ "p_value_ratio": 6.7336210854898174e-34,
296
+ "score": 162.0665949787407
297
+ },
298
+ "generation": [
299
+ 53,
300
+ 116,
301
+ 48,
302
+ 94,
303
+ 47,
304
+ 118,
305
+ 64,
306
+ 123,
307
+ 106,
308
+ 65,
309
+ 59,
310
+ 48,
311
+ 4,
312
+ 86,
313
+ 64,
314
+ 32,
315
+ 84,
316
+ 116,
317
+ 23,
318
+ 23,
319
+ 65,
320
+ 15,
321
+ 50,
322
+ 67,
323
+ 49,
324
+ 69,
325
+ 34,
326
+ 76,
327
+ 1,
328
+ 95,
329
+ 103,
330
+ 120,
331
+ 102,
332
+ 69,
333
+ 125,
334
+ 121,
335
+ 57,
336
+ 39,
337
+ 127,
338
+ 113,
339
+ 98,
340
+ 87,
341
+ 9,
342
+ 51,
343
+ 100,
344
+ 53,
345
+ 46,
346
+ 42,
347
+ 123,
348
+ 55,
349
+ 108,
350
+ 100,
351
+ 50,
352
+ 103,
353
+ 67,
354
+ 80,
355
+ 94,
356
+ 41,
357
+ 97,
358
+ 117,
359
+ 18,
360
+ 66,
361
+ 74,
362
+ 38
363
+ ],
364
+ "resolved": {
365
+ "derived_keys": {
366
+ "key_a": "9864452095710749384",
367
+ "key_b": "10834826187781349534"
368
+ },
369
+ "detector": {
370
+ "alpha": 0.5,
371
+ "context_width": 5,
372
+ "deduplicate_contexts": true,
373
+ "key_b_prf_key": "10834826187781349534",
374
+ "p_value_threshold": 0.01,
375
+ "prf_key": "9864452095710749384",
376
+ "type": "DualKeyGumbelWatermarkDetector"
377
+ },
378
+ "watermark_config": {
379
+ "algorithm": "dual_key_gumbel",
380
+ "allow_target_only_watermarking": false,
381
+ "alpha": 0.5,
382
+ "context_width": 5,
383
+ "deduplicate_contexts": "single_turn",
384
+ "deduplicate_contexts_max_history": 8192,
385
+ "prf": "philox"
386
+ }
387
+ },
388
+ "trace": {
389
+ "dedup_skips": 0,
390
+ "key_b_effective": 33,
391
+ "key_b_routed": 33,
392
+ "partial_context_skips": 0,
393
+ "routing_draws": 64
394
+ }
395
+ },
396
+ "dual-key-gumbel-philox-key42-cw4-alpha-mismatch": {
397
+ "configuration": {
398
+ "detection_key": "42",
399
+ "fixture": {
400
+ "dominant_bias": 0,
401
+ "dominant_token": null,
402
+ "logit_denominator": 16,
403
+ "logit_modulus": 131,
404
+ "num_tokens": 64,
405
+ "prompt": [],
406
+ "vocabulary_size": 128
407
+ },
408
+ "key": "42",
409
+ "prf": "philox",
410
+ "prf_version": "philox4x32-10-v1",
411
+ "scheme": "dual_key_gumbel",
412
+ "scheme_config": {
413
+ "context_width": 4,
414
+ "detection_alpha": 0.2,
415
+ "detection_deduplicate_contexts": true,
416
+ "generation_alpha": 0.1,
417
+ "generation_deduplicate_contexts": "single_turn",
418
+ "generation_deduplicate_contexts_max_history": 8192,
419
+ "p_value_threshold": 0.01
420
+ }
421
+ },
422
+ "detection": {
423
+ "is_watermarked": true,
424
+ "num_scored_tokens": 64,
425
+ "p_value": 1.6569954931292397e-49,
426
+ "p_value_ratio": 1.6569954931292398e-47,
427
+ "score": 215.24386344560963
428
+ },
429
+ "generation": [
430
+ 46,
431
+ 56,
432
+ 6,
433
+ 122,
434
+ 30,
435
+ 100,
436
+ 121,
437
+ 67,
438
+ 63,
439
+ 116,
440
+ 13,
441
+ 65,
442
+ 90,
443
+ 47,
444
+ 25,
445
+ 88,
446
+ 120,
447
+ 31,
448
+ 2,
449
+ 37,
450
+ 40,
451
+ 34,
452
+ 92,
453
+ 28,
454
+ 45,
455
+ 126,
456
+ 94,
457
+ 90,
458
+ 18,
459
+ 36,
460
+ 74,
461
+ 102,
462
+ 10,
463
+ 13,
464
+ 101,
465
+ 51,
466
+ 29,
467
+ 29,
468
+ 46,
469
+ 81,
470
+ 63,
471
+ 2,
472
+ 29,
473
+ 78,
474
+ 121,
475
+ 89,
476
+ 124,
477
+ 109,
478
+ 123,
479
+ 34,
480
+ 30,
481
+ 93,
482
+ 4,
483
+ 110,
484
+ 28,
485
+ 34,
486
+ 105,
487
+ 41,
488
+ 5,
489
+ 48,
490
+ 81,
491
+ 120,
492
+ 60,
493
+ 70
494
+ ],
495
+ "resolved": {
496
+ "derived_keys": {
497
+ "key_a": "37150756557148556",
498
+ "key_b": "15826636237805488045"
499
+ },
500
+ "detector": {
501
+ "alpha": 0.2,
502
+ "context_width": 4,
503
+ "deduplicate_contexts": true,
504
+ "key_b_prf_key": "15826636237805488045",
505
+ "p_value_threshold": 0.01,
506
+ "prf_key": "37150756557148556",
507
+ "type": "DualKeyGumbelWatermarkDetector"
508
+ },
509
+ "watermark_config": {
510
+ "algorithm": "dual_key_gumbel",
511
+ "allow_target_only_watermarking": false,
512
+ "alpha": 0.1,
513
+ "context_width": 4,
514
+ "deduplicate_contexts": "single_turn",
515
+ "deduplicate_contexts_max_history": 8192,
516
+ "prf": "philox"
517
+ }
518
+ },
519
+ "trace": {
520
+ "dedup_skips": 0,
521
+ "key_b_effective": 7,
522
+ "key_b_routed": 7,
523
+ "partial_context_skips": 0,
524
+ "routing_draws": 64
525
+ }
526
+ },
527
+ "dual-key-gumbel-philox-key7-cw4-near-threshold": {
528
+ "configuration": {
529
+ "detection_key": "7",
530
+ "fixture": {
531
+ "dominant_bias": 0,
532
+ "dominant_token": null,
533
+ "logit_denominator": 16,
534
+ "logit_modulus": 131,
535
+ "num_tokens": 8,
536
+ "prompt": [],
537
+ "vocabulary_size": 16
538
+ },
539
+ "key": "7",
540
+ "prf": "philox",
541
+ "prf_version": "philox4x32-10-v1",
542
+ "scheme": "dual_key_gumbel",
543
+ "scheme_config": {
544
+ "context_width": 4,
545
+ "detection_alpha": 0.1,
546
+ "detection_deduplicate_contexts": true,
547
+ "generation_alpha": 0.1,
548
+ "generation_deduplicate_contexts": "single_turn",
549
+ "generation_deduplicate_contexts_max_history": 8192,
550
+ "p_value_threshold": 0.003
551
+ }
552
+ },
553
+ "detection": {
554
+ "is_watermarked": true,
555
+ "num_scored_tokens": 8,
556
+ "p_value": 0.002130807652336366,
557
+ "p_value_ratio": 0.7102692174454553,
558
+ "score": 17.2829982488662
559
+ },
560
+ "generation": [
561
+ 7,
562
+ 3,
563
+ 13,
564
+ 2,
565
+ 5,
566
+ 1,
567
+ 4,
568
+ 14
569
+ ],
570
+ "resolved": {
571
+ "derived_keys": {
572
+ "key_a": "3490214442843822077",
573
+ "key_b": "7720047515392181251"
574
+ },
575
+ "detector": {
576
+ "alpha": 0.1,
577
+ "context_width": 4,
578
+ "deduplicate_contexts": true,
579
+ "key_b_prf_key": "7720047515392181251",
580
+ "p_value_threshold": 0.003,
581
+ "prf_key": "3490214442843822077",
582
+ "type": "DualKeyGumbelWatermarkDetector"
583
+ },
584
+ "watermark_config": {
585
+ "algorithm": "dual_key_gumbel",
586
+ "allow_target_only_watermarking": false,
587
+ "alpha": 0.1,
588
+ "context_width": 4,
589
+ "deduplicate_contexts": "single_turn",
590
+ "deduplicate_contexts_max_history": 8192,
591
+ "prf": "philox"
592
+ }
593
+ },
594
+ "trace": {
595
+ "dedup_skips": 0,
596
+ "key_b_effective": 1,
597
+ "key_b_routed": 1,
598
+ "partial_context_skips": 0,
599
+ "routing_draws": 8
600
+ }
601
+ },
602
+ "dual-key-gumbel-philox-keymax-cw16-alpha1": {
603
+ "configuration": {
604
+ "detection_key": "18446744073709551615",
605
+ "fixture": {
606
+ "dominant_bias": 0,
607
+ "dominant_token": null,
608
+ "logit_denominator": 16,
609
+ "logit_modulus": 131,
610
+ "num_tokens": 64,
611
+ "prompt": [],
612
+ "vocabulary_size": 128
613
+ },
614
+ "key": "18446744073709551615",
615
+ "prf": "philox",
616
+ "prf_version": "philox4x32-10-v1",
617
+ "scheme": "dual_key_gumbel",
618
+ "scheme_config": {
619
+ "context_width": 16,
620
+ "detection_alpha": 1.0,
621
+ "detection_deduplicate_contexts": true,
622
+ "generation_alpha": 1.0,
623
+ "generation_deduplicate_contexts": "single_turn",
624
+ "generation_deduplicate_contexts_max_history": 8192,
625
+ "p_value_threshold": 0.01
626
+ }
627
+ },
628
+ "detection": {
629
+ "is_watermarked": true,
630
+ "num_scored_tokens": 64,
631
+ "p_value": 2.5582243247165326e-52,
632
+ "p_value_ratio": 2.558224324716533e-50,
633
+ "score": 270.9771333793902
634
+ },
635
+ "generation": [
636
+ 45,
637
+ 3,
638
+ 73,
639
+ 41,
640
+ 47,
641
+ 40,
642
+ 21,
643
+ 85,
644
+ 80,
645
+ 70,
646
+ 34,
647
+ 48,
648
+ 58,
649
+ 47,
650
+ 96,
651
+ 28,
652
+ 56,
653
+ 77,
654
+ 101,
655
+ 30,
656
+ 97,
657
+ 103,
658
+ 96,
659
+ 53,
660
+ 87,
661
+ 37,
662
+ 34,
663
+ 113,
664
+ 33,
665
+ 25,
666
+ 103,
667
+ 113,
668
+ 102,
669
+ 6,
670
+ 101,
671
+ 37,
672
+ 29,
673
+ 75,
674
+ 46,
675
+ 67,
676
+ 105,
677
+ 48,
678
+ 115,
679
+ 51,
680
+ 114,
681
+ 4,
682
+ 0,
683
+ 81,
684
+ 98,
685
+ 35,
686
+ 115,
687
+ 111,
688
+ 7,
689
+ 78,
690
+ 21,
691
+ 52,
692
+ 112,
693
+ 48,
694
+ 19,
695
+ 47,
696
+ 68,
697
+ 17,
698
+ 106,
699
+ 73
700
+ ],
701
+ "resolved": {
702
+ "derived_keys": {
703
+ "key_a": "11075965703501209888",
704
+ "key_b": "7399018451426338514"
705
+ },
706
+ "detector": {
707
+ "alpha": 1.0,
708
+ "context_width": 16,
709
+ "deduplicate_contexts": true,
710
+ "key_b_prf_key": "7399018451426338514",
711
+ "p_value_threshold": 0.01,
712
+ "prf_key": "11075965703501209888",
713
+ "type": "DualKeyGumbelWatermarkDetector"
714
+ },
715
+ "watermark_config": {
716
+ "algorithm": "dual_key_gumbel",
717
+ "allow_target_only_watermarking": false,
718
+ "alpha": 1.0,
719
+ "context_width": 16,
720
+ "deduplicate_contexts": "single_turn",
721
+ "deduplicate_contexts_max_history": 8192,
722
+ "prf": "philox"
723
+ }
724
+ },
725
+ "trace": {
726
+ "dedup_skips": 0,
727
+ "key_b_effective": null,
728
+ "key_b_routed": null,
729
+ "partial_context_skips": 0,
730
+ "routing_draws": 0
731
+ }
732
+ },
733
+ "dual-key-gumbel-philox-keymax-cw4-alpha0.4": {
734
+ "configuration": {
735
+ "detection_key": "18446744073709551615",
736
+ "fixture": {
737
+ "dominant_bias": 0,
738
+ "dominant_token": null,
739
+ "logit_denominator": 16,
740
+ "logit_modulus": 131,
741
+ "num_tokens": 64,
742
+ "prompt": [],
743
+ "vocabulary_size": 128
744
+ },
745
+ "key": "18446744073709551615",
746
+ "prf": "philox",
747
+ "prf_version": "philox4x32-10-v1",
748
+ "scheme": "dual_key_gumbel",
749
+ "scheme_config": {
750
+ "context_width": 4,
751
+ "detection_alpha": 0.4,
752
+ "detection_deduplicate_contexts": true,
753
+ "generation_alpha": 0.4,
754
+ "generation_deduplicate_contexts": "single_turn",
755
+ "generation_deduplicate_contexts_max_history": 8192,
756
+ "p_value_threshold": 0.01
757
+ }
758
+ },
759
+ "detection": {
760
+ "is_watermarked": true,
761
+ "num_scored_tokens": 64,
762
+ "p_value": 5.9713149418801004e-43,
763
+ "p_value_ratio": 5.9713149418801e-41,
764
+ "score": 177.98266424643373
765
+ },
766
+ "generation": [
767
+ 7,
768
+ 42,
769
+ 13,
770
+ 55,
771
+ 103,
772
+ 125,
773
+ 96,
774
+ 85,
775
+ 119,
776
+ 38,
777
+ 101,
778
+ 108,
779
+ 72,
780
+ 8,
781
+ 96,
782
+ 120,
783
+ 116,
784
+ 109,
785
+ 119,
786
+ 62,
787
+ 26,
788
+ 107,
789
+ 63,
790
+ 113,
791
+ 102,
792
+ 34,
793
+ 83,
794
+ 90,
795
+ 121,
796
+ 53,
797
+ 18,
798
+ 67,
799
+ 20,
800
+ 12,
801
+ 101,
802
+ 40,
803
+ 86,
804
+ 89,
805
+ 59,
806
+ 81,
807
+ 24,
808
+ 20,
809
+ 72,
810
+ 51,
811
+ 22,
812
+ 117,
813
+ 14,
814
+ 88,
815
+ 116,
816
+ 44,
817
+ 100,
818
+ 118,
819
+ 75,
820
+ 7,
821
+ 10,
822
+ 70,
823
+ 91,
824
+ 5,
825
+ 33,
826
+ 22,
827
+ 4,
828
+ 71,
829
+ 31,
830
+ 121
831
+ ],
832
+ "resolved": {
833
+ "derived_keys": {
834
+ "key_a": "11075965703501209888",
835
+ "key_b": "7399018451426338514"
836
+ },
837
+ "detector": {
838
+ "alpha": 0.4,
839
+ "context_width": 4,
840
+ "deduplicate_contexts": true,
841
+ "key_b_prf_key": "7399018451426338514",
842
+ "p_value_threshold": 0.01,
843
+ "prf_key": "11075965703501209888",
844
+ "type": "DualKeyGumbelWatermarkDetector"
845
+ },
846
+ "watermark_config": {
847
+ "algorithm": "dual_key_gumbel",
848
+ "allow_target_only_watermarking": false,
849
+ "alpha": 0.4,
850
+ "context_width": 4,
851
+ "deduplicate_contexts": "single_turn",
852
+ "deduplicate_contexts_max_history": 8192,
853
+ "prf": "philox"
854
+ }
855
+ },
856
+ "trace": {
857
+ "dedup_skips": 0,
858
+ "key_b_effective": 26,
859
+ "key_b_routed": 26,
860
+ "partial_context_skips": 0,
861
+ "routing_draws": 64
862
+ }
863
+ },
864
+ "dual-key-gumbel-philox-repeated-cw1": {
865
+ "configuration": {
866
+ "detection_key": "42",
867
+ "fixture": {
868
+ "dominant_bias": 52,
869
+ "dominant_token": 3,
870
+ "logit_denominator": 16,
871
+ "logit_modulus": 131,
872
+ "num_tokens": 48,
873
+ "prompt": [],
874
+ "vocabulary_size": 16
875
+ },
876
+ "key": "42",
877
+ "prf": "philox",
878
+ "prf_version": "philox4x32-10-v1",
879
+ "scheme": "dual_key_gumbel",
880
+ "scheme_config": {
881
+ "context_width": 1,
882
+ "detection_alpha": 0.1,
883
+ "detection_deduplicate_contexts": true,
884
+ "generation_alpha": 0.1,
885
+ "generation_deduplicate_contexts": "single_turn",
886
+ "generation_deduplicate_contexts_max_history": 8192,
887
+ "p_value_threshold": 0.01
888
+ }
889
+ },
890
+ "detection": {
891
+ "is_watermarked": true,
892
+ "num_scored_tokens": 13,
893
+ "p_value": 0.002750266035191538,
894
+ "p_value_ratio": 0.2750266035191538,
895
+ "score": 23.896456918277963
896
+ },
897
+ "generation": [
898
+ 3,
899
+ 3,
900
+ 6,
901
+ 9,
902
+ 12,
903
+ 3,
904
+ 3,
905
+ 3,
906
+ 3,
907
+ 10,
908
+ 13,
909
+ 2,
910
+ 1,
911
+ 1,
912
+ 3,
913
+ 3,
914
+ 3,
915
+ 6,
916
+ 2,
917
+ 5,
918
+ 12,
919
+ 8,
920
+ 4,
921
+ 14,
922
+ 3,
923
+ 6,
924
+ 2,
925
+ 5,
926
+ 1,
927
+ 3,
928
+ 3,
929
+ 3,
930
+ 10,
931
+ 6,
932
+ 2,
933
+ 5,
934
+ 1,
935
+ 3,
936
+ 3,
937
+ 3,
938
+ 6,
939
+ 13,
940
+ 9,
941
+ 5,
942
+ 1,
943
+ 3,
944
+ 3,
945
+ 3
946
+ ],
947
+ "resolved": {
948
+ "derived_keys": {
949
+ "key_a": "37150756557148556",
950
+ "key_b": "15826636237805488045"
951
+ },
952
+ "detector": {
953
+ "alpha": 0.1,
954
+ "context_width": 1,
955
+ "deduplicate_contexts": true,
956
+ "key_b_prf_key": "15826636237805488045",
957
+ "p_value_threshold": 0.01,
958
+ "prf_key": "37150756557148556",
959
+ "type": "DualKeyGumbelWatermarkDetector"
960
+ },
961
+ "watermark_config": {
962
+ "algorithm": "dual_key_gumbel",
963
+ "allow_target_only_watermarking": false,
964
+ "alpha": 0.1,
965
+ "context_width": 1,
966
+ "deduplicate_contexts": "single_turn",
967
+ "deduplicate_contexts_max_history": 8192,
968
+ "prf": "philox"
969
+ }
970
+ },
971
+ "trace": {
972
+ "dedup_skips": 35,
973
+ "key_b_effective": 1,
974
+ "key_b_routed": 4,
975
+ "partial_context_skips": 0,
976
+ "routing_draws": 48
977
+ }
978
+ },
979
+ "dual-key-gumbel-philox-repeated-cw4-all": {
980
+ "configuration": {
981
+ "detection_key": "42",
982
+ "fixture": {
983
+ "dominant_bias": 52,
984
+ "dominant_token": 3,
985
+ "logit_denominator": 16,
986
+ "logit_modulus": 131,
987
+ "num_tokens": 48,
988
+ "prompt": [],
989
+ "vocabulary_size": 16
990
+ },
991
+ "key": "42",
992
+ "prf": "philox",
993
+ "prf_version": "philox4x32-10-v1",
994
+ "scheme": "dual_key_gumbel",
995
+ "scheme_config": {
996
+ "context_width": 4,
997
+ "detection_alpha": 0.1,
998
+ "detection_deduplicate_contexts": true,
999
+ "generation_alpha": 0.1,
1000
+ "generation_deduplicate_contexts": "all",
1001
+ "generation_deduplicate_contexts_max_history": 8192,
1002
+ "p_value_threshold": 0.01
1003
+ }
1004
+ },
1005
+ "detection": {
1006
+ "is_watermarked": true,
1007
+ "num_scored_tokens": 47,
1008
+ "p_value": 8.656644652657153e-07,
1009
+ "p_value_ratio": 8.656644652657152e-05,
1010
+ "score": 82.86886159792212
1011
+ },
1012
+ "generation": [
1013
+ 3,
1014
+ 3,
1015
+ 6,
1016
+ 2,
1017
+ 3,
1018
+ 1,
1019
+ 11,
1020
+ 0,
1021
+ 14,
1022
+ 10,
1023
+ 5,
1024
+ 15,
1025
+ 5,
1026
+ 3,
1027
+ 7,
1028
+ 7,
1029
+ 3,
1030
+ 15,
1031
+ 9,
1032
+ 12,
1033
+ 11,
1034
+ 3,
1035
+ 14,
1036
+ 3,
1037
+ 3,
1038
+ 6,
1039
+ 2,
1040
+ 5,
1041
+ 8,
1042
+ 11,
1043
+ 3,
1044
+ 3,
1045
+ 10,
1046
+ 13,
1047
+ 2,
1048
+ 12,
1049
+ 1,
1050
+ 3,
1051
+ 3,
1052
+ 3,
1053
+ 13,
1054
+ 13,
1055
+ 9,
1056
+ 12,
1057
+ 3,
1058
+ 3,
1059
+ 3,
1060
+ 3
1061
+ ],
1062
+ "resolved": {
1063
+ "derived_keys": {
1064
+ "key_a": "37150756557148556",
1065
+ "key_b": "15826636237805488045"
1066
+ },
1067
+ "detector": {
1068
+ "alpha": 0.1,
1069
+ "context_width": 4,
1070
+ "deduplicate_contexts": true,
1071
+ "key_b_prf_key": "15826636237805488045",
1072
+ "p_value_threshold": 0.01,
1073
+ "prf_key": "37150756557148556",
1074
+ "type": "DualKeyGumbelWatermarkDetector"
1075
+ },
1076
+ "watermark_config": {
1077
+ "algorithm": "dual_key_gumbel",
1078
+ "allow_target_only_watermarking": false,
1079
+ "alpha": 0.1,
1080
+ "context_width": 4,
1081
+ "deduplicate_contexts": "all",
1082
+ "deduplicate_contexts_max_history": 8192,
1083
+ "prf": "philox"
1084
+ }
1085
+ },
1086
+ "trace": {
1087
+ "dedup_skips": 5,
1088
+ "key_b_effective": 4,
1089
+ "key_b_routed": 4,
1090
+ "partial_context_skips": 4,
1091
+ "routing_draws": 48
1092
+ }
1093
+ },
1094
+ "gumbel-philox-key0-cw1": {
1095
+ "configuration": {
1096
+ "detection_key": "0",
1097
+ "fixture": {
1098
+ "dominant_bias": 0,
1099
+ "dominant_token": null,
1100
+ "logit_denominator": 16,
1101
+ "logit_modulus": 131,
1102
+ "num_tokens": 64,
1103
+ "prompt": [],
1104
+ "vocabulary_size": 128
1105
+ },
1106
+ "key": "0",
1107
+ "prf": "philox",
1108
+ "prf_version": "philox4x32-10-v1",
1109
+ "scheme": "gumbel",
1110
+ "scheme_config": {
1111
+ "context_width": 1,
1112
+ "detection_alpha": 0.1,
1113
+ "detection_deduplicate_contexts": true,
1114
+ "generation_alpha": 0.1,
1115
+ "generation_deduplicate_contexts": "single_turn",
1116
+ "generation_deduplicate_contexts_max_history": 8192,
1117
+ "p_value_threshold": 0.01
1118
+ }
1119
+ },
1120
+ "detection": {
1121
+ "is_watermarked": true,
1122
+ "num_scored_tokens": 54,
1123
+ "p_value": 4.532248480235615e-47,
1124
+ "p_value_ratio": 4.532248480235615e-45,
1125
+ "score": 236.2768211235414
1126
+ },
1127
+ "generation": [
1128
+ 24,
1129
+ 42,
1130
+ 66,
1131
+ 26,
1132
+ 51,
1133
+ 107,
1134
+ 36,
1135
+ 25,
1136
+ 63,
1137
+ 24,
1138
+ 6,
1139
+ 48,
1140
+ 65,
1141
+ 124,
1142
+ 117,
1143
+ 85,
1144
+ 45,
1145
+ 112,
1146
+ 48,
1147
+ 101,
1148
+ 19,
1149
+ 22,
1150
+ 89,
1151
+ 88,
1152
+ 63,
1153
+ 77,
1154
+ 115,
1155
+ 104,
1156
+ 65,
1157
+ 61,
1158
+ 32,
1159
+ 20,
1160
+ 95,
1161
+ 98,
1162
+ 30,
1163
+ 58,
1164
+ 86,
1165
+ 50,
1166
+ 39,
1167
+ 113,
1168
+ 122,
1169
+ 62,
1170
+ 69,
1171
+ 40,
1172
+ 29,
1173
+ 92,
1174
+ 113,
1175
+ 120,
1176
+ 52,
1177
+ 112,
1178
+ 108,
1179
+ 1,
1180
+ 25,
1181
+ 96,
1182
+ 3,
1183
+ 95,
1184
+ 84,
1185
+ 65,
1186
+ 76,
1187
+ 3,
1188
+ 68,
1189
+ 71,
1190
+ 81,
1191
+ 56
1192
+ ],
1193
+ "resolved": {
1194
+ "derived_keys": {
1195
+ "key_a": null,
1196
+ "key_b": null
1197
+ },
1198
+ "detector": {
1199
+ "alpha": null,
1200
+ "context_width": 1,
1201
+ "deduplicate_contexts": true,
1202
+ "key_b_prf_key": null,
1203
+ "p_value_threshold": 0.01,
1204
+ "prf_key": "0",
1205
+ "type": "GumbelWatermarkDetector"
1206
+ },
1207
+ "watermark_config": {
1208
+ "algorithm": "gumbel",
1209
+ "allow_target_only_watermarking": false,
1210
+ "alpha": 0.1,
1211
+ "context_width": 1,
1212
+ "deduplicate_contexts": "single_turn",
1213
+ "deduplicate_contexts_max_history": 8192,
1214
+ "prf": "philox"
1215
+ }
1216
+ },
1217
+ "trace": {
1218
+ "dedup_skips": 10,
1219
+ "key_b_effective": null,
1220
+ "key_b_routed": null,
1221
+ "partial_context_skips": 0,
1222
+ "routing_draws": 0
1223
+ }
1224
+ },
1225
+ "gumbel-philox-key2p32-cw5-no-dedup": {
1226
+ "configuration": {
1227
+ "detection_key": "4294967296",
1228
+ "fixture": {
1229
+ "dominant_bias": 0,
1230
+ "dominant_token": null,
1231
+ "logit_denominator": 16,
1232
+ "logit_modulus": 131,
1233
+ "num_tokens": 64,
1234
+ "prompt": [],
1235
+ "vocabulary_size": 128
1236
+ },
1237
+ "key": "4294967296",
1238
+ "prf": "philox",
1239
+ "prf_version": "philox4x32-10-v1",
1240
+ "scheme": "gumbel",
1241
+ "scheme_config": {
1242
+ "context_width": 5,
1243
+ "detection_alpha": 0.1,
1244
+ "detection_deduplicate_contexts": false,
1245
+ "generation_alpha": 0.1,
1246
+ "generation_deduplicate_contexts": "none",
1247
+ "generation_deduplicate_contexts_max_history": 8192,
1248
+ "p_value_threshold": 0.01
1249
+ }
1250
+ },
1251
+ "detection": {
1252
+ "is_watermarked": true,
1253
+ "num_scored_tokens": 64,
1254
+ "p_value": 1.1027575381260964e-49,
1255
+ "p_value_ratio": 1.1027575381260964e-47,
1256
+ "score": 263.04926919645095
1257
+ },
1258
+ "generation": [
1259
+ 21,
1260
+ 10,
1261
+ 73,
1262
+ 94,
1263
+ 19,
1264
+ 61,
1265
+ 85,
1266
+ 42,
1267
+ 95,
1268
+ 116,
1269
+ 105,
1270
+ 47,
1271
+ 58,
1272
+ 36,
1273
+ 74,
1274
+ 42,
1275
+ 95,
1276
+ 70,
1277
+ 34,
1278
+ 37,
1279
+ 125,
1280
+ 29,
1281
+ 64,
1282
+ 85,
1283
+ 70,
1284
+ 73,
1285
+ 44,
1286
+ 90,
1287
+ 47,
1288
+ 107,
1289
+ 25,
1290
+ 70,
1291
+ 98,
1292
+ 41,
1293
+ 1,
1294
+ 51,
1295
+ 8,
1296
+ 57,
1297
+ 99,
1298
+ 88,
1299
+ 80,
1300
+ 119,
1301
+ 55,
1302
+ 15,
1303
+ 121,
1304
+ 43,
1305
+ 124,
1306
+ 56,
1307
+ 34,
1308
+ 87,
1309
+ 115,
1310
+ 65,
1311
+ 4,
1312
+ 110,
1313
+ 53,
1314
+ 77,
1315
+ 58,
1316
+ 126,
1317
+ 19,
1318
+ 72,
1319
+ 64,
1320
+ 113,
1321
+ 109,
1322
+ 123
1323
+ ],
1324
+ "resolved": {
1325
+ "derived_keys": {
1326
+ "key_a": null,
1327
+ "key_b": null
1328
+ },
1329
+ "detector": {
1330
+ "alpha": null,
1331
+ "context_width": 5,
1332
+ "deduplicate_contexts": false,
1333
+ "key_b_prf_key": null,
1334
+ "p_value_threshold": 0.01,
1335
+ "prf_key": "4294967296",
1336
+ "type": "GumbelWatermarkDetector"
1337
+ },
1338
+ "watermark_config": {
1339
+ "algorithm": "gumbel",
1340
+ "allow_target_only_watermarking": false,
1341
+ "alpha": 0.1,
1342
+ "context_width": 5,
1343
+ "deduplicate_contexts": "none",
1344
+ "deduplicate_contexts_max_history": 8192,
1345
+ "prf": "philox"
1346
+ }
1347
+ },
1348
+ "trace": {
1349
+ "dedup_skips": 0,
1350
+ "key_b_effective": null,
1351
+ "key_b_routed": null,
1352
+ "partial_context_skips": 0,
1353
+ "routing_draws": 0
1354
+ }
1355
+ },
1356
+ "gumbel-philox-key42-cw4": {
1357
+ "configuration": {
1358
+ "detection_key": "42",
1359
+ "fixture": {
1360
+ "dominant_bias": 0,
1361
+ "dominant_token": null,
1362
+ "logit_denominator": 16,
1363
+ "logit_modulus": 131,
1364
+ "num_tokens": 64,
1365
+ "prompt": [],
1366
+ "vocabulary_size": 128
1367
+ },
1368
+ "key": "42",
1369
+ "prf": "philox",
1370
+ "prf_version": "philox4x32-10-v1",
1371
+ "scheme": "gumbel",
1372
+ "scheme_config": {
1373
+ "context_width": 4,
1374
+ "detection_alpha": 0.1,
1375
+ "detection_deduplicate_contexts": true,
1376
+ "generation_alpha": 0.1,
1377
+ "generation_deduplicate_contexts": "single_turn",
1378
+ "generation_deduplicate_contexts_max_history": 8192,
1379
+ "p_value_threshold": 0.01
1380
+ }
1381
+ },
1382
+ "detection": {
1383
+ "is_watermarked": true,
1384
+ "num_scored_tokens": 64,
1385
+ "p_value": 7.128196280874065e-61,
1386
+ "p_value_ratio": 7.128196280874065e-59,
1387
+ "score": 296.27295787856264
1388
+ },
1389
+ "generation": [
1390
+ 46,
1391
+ 24,
1392
+ 45,
1393
+ 80,
1394
+ 14,
1395
+ 26,
1396
+ 22,
1397
+ 124,
1398
+ 21,
1399
+ 45,
1400
+ 16,
1401
+ 30,
1402
+ 5,
1403
+ 89,
1404
+ 0,
1405
+ 10,
1406
+ 27,
1407
+ 70,
1408
+ 80,
1409
+ 62,
1410
+ 1,
1411
+ 11,
1412
+ 117,
1413
+ 53,
1414
+ 10,
1415
+ 45,
1416
+ 94,
1417
+ 37,
1418
+ 43,
1419
+ 22,
1420
+ 78,
1421
+ 49,
1422
+ 119,
1423
+ 9,
1424
+ 22,
1425
+ 118,
1426
+ 82,
1427
+ 75,
1428
+ 32,
1429
+ 24,
1430
+ 84,
1431
+ 27,
1432
+ 122,
1433
+ 66,
1434
+ 78,
1435
+ 64,
1436
+ 124,
1437
+ 17,
1438
+ 91,
1439
+ 12,
1440
+ 51,
1441
+ 15,
1442
+ 75,
1443
+ 64,
1444
+ 127,
1445
+ 45,
1446
+ 112,
1447
+ 15,
1448
+ 83,
1449
+ 114,
1450
+ 121,
1451
+ 109,
1452
+ 24,
1453
+ 77
1454
+ ],
1455
+ "resolved": {
1456
+ "derived_keys": {
1457
+ "key_a": null,
1458
+ "key_b": null
1459
+ },
1460
+ "detector": {
1461
+ "alpha": null,
1462
+ "context_width": 4,
1463
+ "deduplicate_contexts": true,
1464
+ "key_b_prf_key": null,
1465
+ "p_value_threshold": 0.01,
1466
+ "prf_key": "42",
1467
+ "type": "GumbelWatermarkDetector"
1468
+ },
1469
+ "watermark_config": {
1470
+ "algorithm": "gumbel",
1471
+ "allow_target_only_watermarking": false,
1472
+ "alpha": 0.1,
1473
+ "context_width": 4,
1474
+ "deduplicate_contexts": "single_turn",
1475
+ "deduplicate_contexts_max_history": 8192,
1476
+ "prf": "philox"
1477
+ }
1478
+ },
1479
+ "trace": {
1480
+ "dedup_skips": 0,
1481
+ "key_b_effective": null,
1482
+ "key_b_routed": null,
1483
+ "partial_context_skips": 0,
1484
+ "routing_draws": 0
1485
+ }
1486
+ },
1487
+ "gumbel-philox-key42-cw4-all": {
1488
+ "configuration": {
1489
+ "detection_key": "42",
1490
+ "fixture": {
1491
+ "dominant_bias": 0,
1492
+ "dominant_token": null,
1493
+ "logit_denominator": 16,
1494
+ "logit_modulus": 131,
1495
+ "num_tokens": 64,
1496
+ "prompt": [],
1497
+ "vocabulary_size": 128
1498
+ },
1499
+ "key": "42",
1500
+ "prf": "philox",
1501
+ "prf_version": "philox4x32-10-v1",
1502
+ "scheme": "gumbel",
1503
+ "scheme_config": {
1504
+ "context_width": 4,
1505
+ "detection_alpha": 0.1,
1506
+ "detection_deduplicate_contexts": true,
1507
+ "generation_alpha": 0.1,
1508
+ "generation_deduplicate_contexts": "all",
1509
+ "generation_deduplicate_contexts_max_history": 8192,
1510
+ "p_value_threshold": 0.01
1511
+ }
1512
+ },
1513
+ "detection": {
1514
+ "is_watermarked": true,
1515
+ "num_scored_tokens": 64,
1516
+ "p_value": 6.0283750962334736e-55,
1517
+ "p_value_ratio": 6.028375096233473e-53,
1518
+ "score": 278.8159437407263
1519
+ },
1520
+ "generation": [
1521
+ 46,
1522
+ 42,
1523
+ 38,
1524
+ 34,
1525
+ 122,
1526
+ 33,
1527
+ 43,
1528
+ 117,
1529
+ 24,
1530
+ 52,
1531
+ 29,
1532
+ 115,
1533
+ 12,
1534
+ 32,
1535
+ 121,
1536
+ 124,
1537
+ 81,
1538
+ 45,
1539
+ 112,
1540
+ 16,
1541
+ 1,
1542
+ 100,
1543
+ 11,
1544
+ 46,
1545
+ 95,
1546
+ 77,
1547
+ 80,
1548
+ 5,
1549
+ 53,
1550
+ 114,
1551
+ 64,
1552
+ 67,
1553
+ 37,
1554
+ 52,
1555
+ 62,
1556
+ 125,
1557
+ 107,
1558
+ 75,
1559
+ 39,
1560
+ 28,
1561
+ 126,
1562
+ 20,
1563
+ 23,
1564
+ 61,
1565
+ 54,
1566
+ 3,
1567
+ 116,
1568
+ 10,
1569
+ 59,
1570
+ 27,
1571
+ 58,
1572
+ 104,
1573
+ 124,
1574
+ 2,
1575
+ 28,
1576
+ 38,
1577
+ 91,
1578
+ 101,
1579
+ 118,
1580
+ 103,
1581
+ 46,
1582
+ 110,
1583
+ 70,
1584
+ 45
1585
+ ],
1586
+ "resolved": {
1587
+ "derived_keys": {
1588
+ "key_a": null,
1589
+ "key_b": null
1590
+ },
1591
+ "detector": {
1592
+ "alpha": null,
1593
+ "context_width": 4,
1594
+ "deduplicate_contexts": true,
1595
+ "key_b_prf_key": null,
1596
+ "p_value_threshold": 0.01,
1597
+ "prf_key": "42",
1598
+ "type": "GumbelWatermarkDetector"
1599
+ },
1600
+ "watermark_config": {
1601
+ "algorithm": "gumbel",
1602
+ "allow_target_only_watermarking": false,
1603
+ "alpha": 0.1,
1604
+ "context_width": 4,
1605
+ "deduplicate_contexts": "all",
1606
+ "deduplicate_contexts_max_history": 8192,
1607
+ "prf": "philox"
1608
+ }
1609
+ },
1610
+ "trace": {
1611
+ "dedup_skips": 4,
1612
+ "key_b_effective": null,
1613
+ "key_b_routed": null,
1614
+ "partial_context_skips": 4,
1615
+ "routing_draws": 0
1616
+ }
1617
+ },
1618
+ "gumbel-philox-key42-cw4-all-prompt": {
1619
+ "configuration": {
1620
+ "detection_key": "42",
1621
+ "fixture": {
1622
+ "dominant_bias": 0,
1623
+ "dominant_token": null,
1624
+ "logit_denominator": 16,
1625
+ "logit_modulus": 131,
1626
+ "num_tokens": 64,
1627
+ "prompt": [
1628
+ 46,
1629
+ 42,
1630
+ 38,
1631
+ 34,
1632
+ 122
1633
+ ],
1634
+ "vocabulary_size": 128
1635
+ },
1636
+ "key": "42",
1637
+ "prf": "philox",
1638
+ "prf_version": "philox4x32-10-v1",
1639
+ "scheme": "gumbel",
1640
+ "scheme_config": {
1641
+ "context_width": 4,
1642
+ "detection_alpha": 0.1,
1643
+ "detection_deduplicate_contexts": true,
1644
+ "generation_alpha": 0.1,
1645
+ "generation_deduplicate_contexts": "all",
1646
+ "generation_deduplicate_contexts_max_history": 8192,
1647
+ "p_value_threshold": 0.01
1648
+ }
1649
+ },
1650
+ "detection": {
1651
+ "is_watermarked": true,
1652
+ "num_scored_tokens": 64,
1653
+ "p_value": 4.330336079473992e-56,
1654
+ "p_value_ratio": 4.3303360794739913e-54,
1655
+ "score": 282.2076506349452
1656
+ },
1657
+ "generation": [
1658
+ 46,
1659
+ 42,
1660
+ 38,
1661
+ 34,
1662
+ 30,
1663
+ 43,
1664
+ 121,
1665
+ 123,
1666
+ 91,
1667
+ 17,
1668
+ 66,
1669
+ 58,
1670
+ 54,
1671
+ 103,
1672
+ 28,
1673
+ 39,
1674
+ 3,
1675
+ 34,
1676
+ 58,
1677
+ 23,
1678
+ 21,
1679
+ 29,
1680
+ 57,
1681
+ 9,
1682
+ 66,
1683
+ 91,
1684
+ 101,
1685
+ 58,
1686
+ 85,
1687
+ 67,
1688
+ 18,
1689
+ 102,
1690
+ 123,
1691
+ 112,
1692
+ 2,
1693
+ 37,
1694
+ 100,
1695
+ 32,
1696
+ 35,
1697
+ 67,
1698
+ 116,
1699
+ 115,
1700
+ 108,
1701
+ 5,
1702
+ 100,
1703
+ 14,
1704
+ 67,
1705
+ 56,
1706
+ 122,
1707
+ 23,
1708
+ 12,
1709
+ 125,
1710
+ 103,
1711
+ 20,
1712
+ 70,
1713
+ 8,
1714
+ 45,
1715
+ 1,
1716
+ 90,
1717
+ 45,
1718
+ 114,
1719
+ 10,
1720
+ 30,
1721
+ 66
1722
+ ],
1723
+ "resolved": {
1724
+ "derived_keys": {
1725
+ "key_a": null,
1726
+ "key_b": null
1727
+ },
1728
+ "detector": {
1729
+ "alpha": null,
1730
+ "context_width": 4,
1731
+ "deduplicate_contexts": true,
1732
+ "key_b_prf_key": null,
1733
+ "p_value_threshold": 0.01,
1734
+ "prf_key": "42",
1735
+ "type": "GumbelWatermarkDetector"
1736
+ },
1737
+ "watermark_config": {
1738
+ "algorithm": "gumbel",
1739
+ "allow_target_only_watermarking": false,
1740
+ "alpha": 0.1,
1741
+ "context_width": 4,
1742
+ "deduplicate_contexts": "all",
1743
+ "deduplicate_contexts_max_history": 8192,
1744
+ "prf": "philox"
1745
+ }
1746
+ },
1747
+ "trace": {
1748
+ "dedup_skips": 5,
1749
+ "key_b_effective": null,
1750
+ "key_b_routed": null,
1751
+ "partial_context_skips": 4,
1752
+ "routing_draws": 0
1753
+ }
1754
+ },
1755
+ "gumbel-philox-key42-cw4-mid-all": {
1756
+ "configuration": {
1757
+ "detection_key": "42",
1758
+ "fixture": {
1759
+ "dominant_bias": 16,
1760
+ "dominant_token": 3,
1761
+ "logit_denominator": 16,
1762
+ "logit_modulus": 131,
1763
+ "num_tokens": 64,
1764
+ "prompt": [],
1765
+ "vocabulary_size": 8
1766
+ },
1767
+ "key": "42",
1768
+ "prf": "philox",
1769
+ "prf_version": "philox4x32-10-v1",
1770
+ "scheme": "gumbel",
1771
+ "scheme_config": {
1772
+ "context_width": 4,
1773
+ "detection_alpha": 0.1,
1774
+ "detection_deduplicate_contexts": true,
1775
+ "generation_alpha": 0.1,
1776
+ "generation_deduplicate_contexts": "all",
1777
+ "generation_deduplicate_contexts_max_history": null,
1778
+ "p_value_threshold": 0.01
1779
+ }
1780
+ },
1781
+ "detection": {
1782
+ "is_watermarked": true,
1783
+ "num_scored_tokens": 58,
1784
+ "p_value": 1.6692708568346358e-08,
1785
+ "p_value_ratio": 1.6692708568346358e-06,
1786
+ "score": 110.3077257312174
1787
+ },
1788
+ "generation": [
1789
+ 7,
1790
+ 3,
1791
+ 6,
1792
+ 2,
1793
+ 5,
1794
+ 1,
1795
+ 7,
1796
+ 3,
1797
+ 6,
1798
+ 6,
1799
+ 5,
1800
+ 2,
1801
+ 5,
1802
+ 4,
1803
+ 3,
1804
+ 0,
1805
+ 3,
1806
+ 6,
1807
+ 5,
1808
+ 5,
1809
+ 1,
1810
+ 7,
1811
+ 4,
1812
+ 3,
1813
+ 3,
1814
+ 6,
1815
+ 1,
1816
+ 5,
1817
+ 1,
1818
+ 3,
1819
+ 3,
1820
+ 3,
1821
+ 6,
1822
+ 6,
1823
+ 2,
1824
+ 3,
1825
+ 1,
1826
+ 4,
1827
+ 7,
1828
+ 3,
1829
+ 6,
1830
+ 2,
1831
+ 5,
1832
+ 5,
1833
+ 0,
1834
+ 0,
1835
+ 7,
1836
+ 3,
1837
+ 6,
1838
+ 2,
1839
+ 5,
1840
+ 1,
1841
+ 4,
1842
+ 2,
1843
+ 3,
1844
+ 3,
1845
+ 2,
1846
+ 5,
1847
+ 4,
1848
+ 1,
1849
+ 4,
1850
+ 7,
1851
+ 3,
1852
+ 6
1853
+ ],
1854
+ "resolved": {
1855
+ "derived_keys": {
1856
+ "key_a": null,
1857
+ "key_b": null
1858
+ },
1859
+ "detector": {
1860
+ "alpha": null,
1861
+ "context_width": 4,
1862
+ "deduplicate_contexts": true,
1863
+ "key_b_prf_key": null,
1864
+ "p_value_threshold": 0.01,
1865
+ "prf_key": "42",
1866
+ "type": "GumbelWatermarkDetector"
1867
+ },
1868
+ "watermark_config": {
1869
+ "algorithm": "gumbel",
1870
+ "allow_target_only_watermarking": false,
1871
+ "alpha": 0.1,
1872
+ "context_width": 4,
1873
+ "deduplicate_contexts": "all",
1874
+ "deduplicate_contexts_max_history": null,
1875
+ "prf": "philox"
1876
+ }
1877
+ },
1878
+ "trace": {
1879
+ "dedup_skips": 10,
1880
+ "key_b_effective": null,
1881
+ "key_b_routed": null,
1882
+ "partial_context_skips": 4,
1883
+ "routing_draws": 0
1884
+ }
1885
+ },
1886
+ "gumbel-philox-key42-cw4-mid-history-none": {
1887
+ "configuration": {
1888
+ "detection_key": "42",
1889
+ "fixture": {
1890
+ "dominant_bias": 16,
1891
+ "dominant_token": 3,
1892
+ "logit_denominator": 16,
1893
+ "logit_modulus": 131,
1894
+ "num_tokens": 64,
1895
+ "prompt": [],
1896
+ "vocabulary_size": 8
1897
+ },
1898
+ "key": "42",
1899
+ "prf": "philox",
1900
+ "prf_version": "philox4x32-10-v1",
1901
+ "scheme": "gumbel",
1902
+ "scheme_config": {
1903
+ "context_width": 4,
1904
+ "detection_alpha": 0.1,
1905
+ "detection_deduplicate_contexts": true,
1906
+ "generation_alpha": 0.1,
1907
+ "generation_deduplicate_contexts": "single_turn",
1908
+ "generation_deduplicate_contexts_max_history": null,
1909
+ "p_value_threshold": 0.01
1910
+ }
1911
+ },
1912
+ "detection": {
1913
+ "is_watermarked": true,
1914
+ "num_scored_tokens": 58,
1915
+ "p_value": 1.3019898400616044e-08,
1916
+ "p_value_ratio": 1.3019898400616043e-06,
1917
+ "score": 110.81134114351678
1918
+ },
1919
+ "generation": [
1920
+ 7,
1921
+ 2,
1922
+ 2,
1923
+ 5,
1924
+ 5,
1925
+ 4,
1926
+ 4,
1927
+ 0,
1928
+ 3,
1929
+ 2,
1930
+ 6,
1931
+ 2,
1932
+ 5,
1933
+ 1,
1934
+ 7,
1935
+ 3,
1936
+ 6,
1937
+ 6,
1938
+ 5,
1939
+ 5,
1940
+ 7,
1941
+ 0,
1942
+ 3,
1943
+ 0,
1944
+ 3,
1945
+ 6,
1946
+ 5,
1947
+ 5,
1948
+ 1,
1949
+ 7,
1950
+ 7,
1951
+ 3,
1952
+ 6,
1953
+ 2,
1954
+ 2,
1955
+ 5,
1956
+ 1,
1957
+ 4,
1958
+ 2,
1959
+ 3,
1960
+ 5,
1961
+ 2,
1962
+ 5,
1963
+ 4,
1964
+ 3,
1965
+ 4,
1966
+ 0,
1967
+ 6,
1968
+ 6,
1969
+ 5,
1970
+ 5,
1971
+ 1,
1972
+ 4,
1973
+ 7,
1974
+ 7,
1975
+ 3,
1976
+ 6,
1977
+ 2,
1978
+ 5,
1979
+ 1,
1980
+ 4,
1981
+ 0,
1982
+ 3,
1983
+ 6
1984
+ ],
1985
+ "resolved": {
1986
+ "derived_keys": {
1987
+ "key_a": null,
1988
+ "key_b": null
1989
+ },
1990
+ "detector": {
1991
+ "alpha": null,
1992
+ "context_width": 4,
1993
+ "deduplicate_contexts": true,
1994
+ "key_b_prf_key": null,
1995
+ "p_value_threshold": 0.01,
1996
+ "prf_key": "42",
1997
+ "type": "GumbelWatermarkDetector"
1998
+ },
1999
+ "watermark_config": {
2000
+ "algorithm": "gumbel",
2001
+ "allow_target_only_watermarking": false,
2002
+ "alpha": 0.1,
2003
+ "context_width": 4,
2004
+ "deduplicate_contexts": "single_turn",
2005
+ "deduplicate_contexts_max_history": null,
2006
+ "prf": "philox"
2007
+ }
2008
+ },
2009
+ "trace": {
2010
+ "dedup_skips": 6,
2011
+ "key_b_effective": null,
2012
+ "key_b_routed": null,
2013
+ "partial_context_skips": 0,
2014
+ "routing_draws": 0
2015
+ }
2016
+ },
2017
+ "gumbel-philox-key42-cw4-mid-history8": {
2018
+ "configuration": {
2019
+ "detection_key": "42",
2020
+ "fixture": {
2021
+ "dominant_bias": 16,
2022
+ "dominant_token": 3,
2023
+ "logit_denominator": 16,
2024
+ "logit_modulus": 131,
2025
+ "num_tokens": 64,
2026
+ "prompt": [],
2027
+ "vocabulary_size": 8
2028
+ },
2029
+ "key": "42",
2030
+ "prf": "philox",
2031
+ "prf_version": "philox4x32-10-v1",
2032
+ "scheme": "gumbel",
2033
+ "scheme_config": {
2034
+ "context_width": 4,
2035
+ "detection_alpha": 0.1,
2036
+ "detection_deduplicate_contexts": true,
2037
+ "generation_alpha": 0.1,
2038
+ "generation_deduplicate_contexts": "single_turn",
2039
+ "generation_deduplicate_contexts_max_history": 8,
2040
+ "p_value_threshold": 0.01
2041
+ }
2042
+ },
2043
+ "detection": {
2044
+ "is_watermarked": true,
2045
+ "num_scored_tokens": 58,
2046
+ "p_value": 2.772032243308163e-09,
2047
+ "p_value_ratio": 2.772032243308163e-07,
2048
+ "score": 113.89758610123921
2049
+ },
2050
+ "generation": [
2051
+ 7,
2052
+ 2,
2053
+ 2,
2054
+ 5,
2055
+ 5,
2056
+ 4,
2057
+ 4,
2058
+ 0,
2059
+ 3,
2060
+ 2,
2061
+ 6,
2062
+ 2,
2063
+ 5,
2064
+ 1,
2065
+ 7,
2066
+ 3,
2067
+ 6,
2068
+ 6,
2069
+ 5,
2070
+ 5,
2071
+ 7,
2072
+ 0,
2073
+ 3,
2074
+ 0,
2075
+ 3,
2076
+ 6,
2077
+ 5,
2078
+ 5,
2079
+ 1,
2080
+ 7,
2081
+ 7,
2082
+ 3,
2083
+ 6,
2084
+ 2,
2085
+ 2,
2086
+ 5,
2087
+ 1,
2088
+ 4,
2089
+ 2,
2090
+ 3,
2091
+ 5,
2092
+ 2,
2093
+ 5,
2094
+ 4,
2095
+ 3,
2096
+ 4,
2097
+ 0,
2098
+ 6,
2099
+ 6,
2100
+ 5,
2101
+ 5,
2102
+ 7,
2103
+ 0,
2104
+ 3,
2105
+ 7,
2106
+ 3,
2107
+ 2,
2108
+ 2,
2109
+ 5,
2110
+ 4,
2111
+ 4,
2112
+ 0,
2113
+ 3,
2114
+ 2
2115
+ ],
2116
+ "resolved": {
2117
+ "derived_keys": {
2118
+ "key_a": null,
2119
+ "key_b": null
2120
+ },
2121
+ "detector": {
2122
+ "alpha": null,
2123
+ "context_width": 4,
2124
+ "deduplicate_contexts": true,
2125
+ "key_b_prf_key": null,
2126
+ "p_value_threshold": 0.01,
2127
+ "prf_key": "42",
2128
+ "type": "GumbelWatermarkDetector"
2129
+ },
2130
+ "watermark_config": {
2131
+ "algorithm": "gumbel",
2132
+ "allow_target_only_watermarking": false,
2133
+ "alpha": 0.1,
2134
+ "context_width": 4,
2135
+ "deduplicate_contexts": "single_turn",
2136
+ "deduplicate_contexts_max_history": 8,
2137
+ "prf": "philox"
2138
+ }
2139
+ },
2140
+ "trace": {
2141
+ "dedup_skips": 0,
2142
+ "key_b_effective": null,
2143
+ "key_b_routed": null,
2144
+ "partial_context_skips": 0,
2145
+ "routing_draws": 0
2146
+ }
2147
+ },
2148
+ "gumbel-philox-key42-cw4-mid-no-dedup": {
2149
+ "configuration": {
2150
+ "detection_key": "42",
2151
+ "fixture": {
2152
+ "dominant_bias": 16,
2153
+ "dominant_token": 3,
2154
+ "logit_denominator": 16,
2155
+ "logit_modulus": 131,
2156
+ "num_tokens": 64,
2157
+ "prompt": [],
2158
+ "vocabulary_size": 8
2159
+ },
2160
+ "key": "42",
2161
+ "prf": "philox",
2162
+ "prf_version": "philox4x32-10-v1",
2163
+ "scheme": "gumbel",
2164
+ "scheme_config": {
2165
+ "context_width": 4,
2166
+ "detection_alpha": 0.1,
2167
+ "detection_deduplicate_contexts": false,
2168
+ "generation_alpha": 0.1,
2169
+ "generation_deduplicate_contexts": "none",
2170
+ "generation_deduplicate_contexts_max_history": null,
2171
+ "p_value_threshold": 0.01
2172
+ }
2173
+ },
2174
+ "detection": {
2175
+ "is_watermarked": true,
2176
+ "num_scored_tokens": 64,
2177
+ "p_value": 2.136704912577492e-10,
2178
+ "p_value_ratio": 2.136704912577492e-08,
2179
+ "score": 127.21876922102206
2180
+ },
2181
+ "generation": [
2182
+ 7,
2183
+ 2,
2184
+ 2,
2185
+ 5,
2186
+ 5,
2187
+ 4,
2188
+ 4,
2189
+ 0,
2190
+ 3,
2191
+ 2,
2192
+ 6,
2193
+ 2,
2194
+ 5,
2195
+ 1,
2196
+ 7,
2197
+ 3,
2198
+ 6,
2199
+ 6,
2200
+ 5,
2201
+ 5,
2202
+ 7,
2203
+ 0,
2204
+ 3,
2205
+ 0,
2206
+ 3,
2207
+ 6,
2208
+ 5,
2209
+ 5,
2210
+ 1,
2211
+ 7,
2212
+ 7,
2213
+ 3,
2214
+ 6,
2215
+ 2,
2216
+ 2,
2217
+ 5,
2218
+ 1,
2219
+ 4,
2220
+ 2,
2221
+ 3,
2222
+ 5,
2223
+ 2,
2224
+ 5,
2225
+ 4,
2226
+ 3,
2227
+ 4,
2228
+ 0,
2229
+ 6,
2230
+ 6,
2231
+ 5,
2232
+ 5,
2233
+ 7,
2234
+ 0,
2235
+ 3,
2236
+ 7,
2237
+ 3,
2238
+ 2,
2239
+ 2,
2240
+ 5,
2241
+ 4,
2242
+ 4,
2243
+ 0,
2244
+ 3,
2245
+ 2
2246
+ ],
2247
+ "resolved": {
2248
+ "derived_keys": {
2249
+ "key_a": null,
2250
+ "key_b": null
2251
+ },
2252
+ "detector": {
2253
+ "alpha": null,
2254
+ "context_width": 4,
2255
+ "deduplicate_contexts": false,
2256
+ "key_b_prf_key": null,
2257
+ "p_value_threshold": 0.01,
2258
+ "prf_key": "42",
2259
+ "type": "GumbelWatermarkDetector"
2260
+ },
2261
+ "watermark_config": {
2262
+ "algorithm": "gumbel",
2263
+ "allow_target_only_watermarking": false,
2264
+ "alpha": 0.1,
2265
+ "context_width": 4,
2266
+ "deduplicate_contexts": "none",
2267
+ "deduplicate_contexts_max_history": null,
2268
+ "prf": "philox"
2269
+ }
2270
+ },
2271
+ "trace": {
2272
+ "dedup_skips": 0,
2273
+ "key_b_effective": null,
2274
+ "key_b_routed": null,
2275
+ "partial_context_skips": 0,
2276
+ "routing_draws": 0
2277
+ }
2278
+ },
2279
+ "gumbel-philox-key42-cw4-near-threshold": {
2280
+ "configuration": {
2281
+ "detection_key": "42",
2282
+ "fixture": {
2283
+ "dominant_bias": 0,
2284
+ "dominant_token": null,
2285
+ "logit_denominator": 16,
2286
+ "logit_modulus": 131,
2287
+ "num_tokens": 8,
2288
+ "prompt": [],
2289
+ "vocabulary_size": 16
2290
+ },
2291
+ "key": "42",
2292
+ "prf": "philox",
2293
+ "prf_version": "philox4x32-10-v1",
2294
+ "scheme": "gumbel",
2295
+ "scheme_config": {
2296
+ "context_width": 4,
2297
+ "detection_alpha": 0.1,
2298
+ "detection_deduplicate_contexts": true,
2299
+ "generation_alpha": 0.1,
2300
+ "generation_deduplicate_contexts": "single_turn",
2301
+ "generation_deduplicate_contexts_max_history": 8192,
2302
+ "p_value_threshold": 0.0015
2303
+ }
2304
+ },
2305
+ "detection": {
2306
+ "is_watermarked": true,
2307
+ "num_scored_tokens": 8,
2308
+ "p_value": 0.0009697880157637389,
2309
+ "p_value_ratio": 0.6465253438424926,
2310
+ "score": 19.672172609864035
2311
+ },
2312
+ "generation": [
2313
+ 7,
2314
+ 2,
2315
+ 13,
2316
+ 2,
2317
+ 5,
2318
+ 1,
2319
+ 11,
2320
+ 14
2321
+ ],
2322
+ "resolved": {
2323
+ "derived_keys": {
2324
+ "key_a": null,
2325
+ "key_b": null
2326
+ },
2327
+ "detector": {
2328
+ "alpha": null,
2329
+ "context_width": 4,
2330
+ "deduplicate_contexts": true,
2331
+ "key_b_prf_key": null,
2332
+ "p_value_threshold": 0.0015,
2333
+ "prf_key": "42",
2334
+ "type": "GumbelWatermarkDetector"
2335
+ },
2336
+ "watermark_config": {
2337
+ "algorithm": "gumbel",
2338
+ "allow_target_only_watermarking": false,
2339
+ "alpha": 0.1,
2340
+ "context_width": 4,
2341
+ "deduplicate_contexts": "single_turn",
2342
+ "deduplicate_contexts_max_history": 8192,
2343
+ "prf": "philox"
2344
+ }
2345
+ },
2346
+ "trace": {
2347
+ "dedup_skips": 0,
2348
+ "key_b_effective": null,
2349
+ "key_b_routed": null,
2350
+ "partial_context_skips": 0,
2351
+ "routing_draws": 0
2352
+ }
2353
+ },
2354
+ "gumbel-philox-key42-cw4-wrong-key": {
2355
+ "configuration": {
2356
+ "detection_key": "43",
2357
+ "fixture": {
2358
+ "dominant_bias": 0,
2359
+ "dominant_token": null,
2360
+ "logit_denominator": 16,
2361
+ "logit_modulus": 131,
2362
+ "num_tokens": 64,
2363
+ "prompt": [],
2364
+ "vocabulary_size": 128
2365
+ },
2366
+ "key": "42",
2367
+ "prf": "philox",
2368
+ "prf_version": "philox4x32-10-v1",
2369
+ "scheme": "gumbel",
2370
+ "scheme_config": {
2371
+ "context_width": 4,
2372
+ "detection_alpha": 0.1,
2373
+ "detection_deduplicate_contexts": true,
2374
+ "generation_alpha": 0.1,
2375
+ "generation_deduplicate_contexts": "single_turn",
2376
+ "generation_deduplicate_contexts_max_history": 8192,
2377
+ "p_value_threshold": 0.01
2378
+ }
2379
+ },
2380
+ "detection": {
2381
+ "is_watermarked": false,
2382
+ "num_scored_tokens": 64,
2383
+ "p_value": 0.5208447936891313,
2384
+ "p_value_ratio": 52.08447936891313,
2385
+ "score": 63.25096716585621
2386
+ },
2387
+ "generation": [
2388
+ 46,
2389
+ 24,
2390
+ 45,
2391
+ 80,
2392
+ 14,
2393
+ 26,
2394
+ 22,
2395
+ 124,
2396
+ 21,
2397
+ 45,
2398
+ 16,
2399
+ 30,
2400
+ 5,
2401
+ 89,
2402
+ 0,
2403
+ 10,
2404
+ 27,
2405
+ 70,
2406
+ 80,
2407
+ 62,
2408
+ 1,
2409
+ 11,
2410
+ 117,
2411
+ 53,
2412
+ 10,
2413
+ 45,
2414
+ 94,
2415
+ 37,
2416
+ 43,
2417
+ 22,
2418
+ 78,
2419
+ 49,
2420
+ 119,
2421
+ 9,
2422
+ 22,
2423
+ 118,
2424
+ 82,
2425
+ 75,
2426
+ 32,
2427
+ 24,
2428
+ 84,
2429
+ 27,
2430
+ 122,
2431
+ 66,
2432
+ 78,
2433
+ 64,
2434
+ 124,
2435
+ 17,
2436
+ 91,
2437
+ 12,
2438
+ 51,
2439
+ 15,
2440
+ 75,
2441
+ 64,
2442
+ 127,
2443
+ 45,
2444
+ 112,
2445
+ 15,
2446
+ 83,
2447
+ 114,
2448
+ 121,
2449
+ 109,
2450
+ 24,
2451
+ 77
2452
+ ],
2453
+ "resolved": {
2454
+ "derived_keys": {
2455
+ "key_a": null,
2456
+ "key_b": null
2457
+ },
2458
+ "detector": {
2459
+ "alpha": null,
2460
+ "context_width": 4,
2461
+ "deduplicate_contexts": true,
2462
+ "key_b_prf_key": null,
2463
+ "p_value_threshold": 0.01,
2464
+ "prf_key": "43",
2465
+ "type": "GumbelWatermarkDetector"
2466
+ },
2467
+ "watermark_config": {
2468
+ "algorithm": "gumbel",
2469
+ "allow_target_only_watermarking": false,
2470
+ "alpha": 0.1,
2471
+ "context_width": 4,
2472
+ "deduplicate_contexts": "single_turn",
2473
+ "deduplicate_contexts_max_history": 8192,
2474
+ "prf": "philox"
2475
+ }
2476
+ },
2477
+ "trace": {
2478
+ "dedup_skips": 0,
2479
+ "key_b_effective": null,
2480
+ "key_b_routed": null,
2481
+ "partial_context_skips": 0,
2482
+ "routing_draws": 0
2483
+ }
2484
+ },
2485
+ "gumbel-philox-keymax-cw16-all": {
2486
+ "configuration": {
2487
+ "detection_key": "18446744073709551615",
2488
+ "fixture": {
2489
+ "dominant_bias": 0,
2490
+ "dominant_token": null,
2491
+ "logit_denominator": 16,
2492
+ "logit_modulus": 131,
2493
+ "num_tokens": 64,
2494
+ "prompt": [],
2495
+ "vocabulary_size": 128
2496
+ },
2497
+ "key": "18446744073709551615",
2498
+ "prf": "philox",
2499
+ "prf_version": "philox4x32-10-v1",
2500
+ "scheme": "gumbel",
2501
+ "scheme_config": {
2502
+ "context_width": 16,
2503
+ "detection_alpha": 0.1,
2504
+ "detection_deduplicate_contexts": true,
2505
+ "generation_alpha": 0.1,
2506
+ "generation_deduplicate_contexts": "all",
2507
+ "generation_deduplicate_contexts_max_history": 8192,
2508
+ "p_value_threshold": 0.01
2509
+ }
2510
+ },
2511
+ "detection": {
2512
+ "is_watermarked": true,
2513
+ "num_scored_tokens": 64,
2514
+ "p_value": 6.166345567165398e-36,
2515
+ "p_value_ratio": 6.1663455671653984e-34,
2516
+ "score": 220.2767573421712
2517
+ },
2518
+ "generation": [
2519
+ 46,
2520
+ 42,
2521
+ 38,
2522
+ 34,
2523
+ 30,
2524
+ 26,
2525
+ 22,
2526
+ 18,
2527
+ 14,
2528
+ 10,
2529
+ 6,
2530
+ 2,
2531
+ 44,
2532
+ 125,
2533
+ 121,
2534
+ 117,
2535
+ 88,
2536
+ 6,
2537
+ 97,
2538
+ 12,
2539
+ 86,
2540
+ 121,
2541
+ 0,
2542
+ 106,
2543
+ 98,
2544
+ 119,
2545
+ 101,
2546
+ 36,
2547
+ 47,
2548
+ 110,
2549
+ 25,
2550
+ 24,
2551
+ 102,
2552
+ 6,
2553
+ 101,
2554
+ 37,
2555
+ 114,
2556
+ 50,
2557
+ 53,
2558
+ 127,
2559
+ 109,
2560
+ 80,
2561
+ 69,
2562
+ 5,
2563
+ 96,
2564
+ 60,
2565
+ 14,
2566
+ 42,
2567
+ 38,
2568
+ 58,
2569
+ 118,
2570
+ 79,
2571
+ 4,
2572
+ 110,
2573
+ 42,
2574
+ 102,
2575
+ 66,
2576
+ 80,
2577
+ 72,
2578
+ 33,
2579
+ 78,
2580
+ 106,
2581
+ 67,
2582
+ 52
2583
+ ],
2584
+ "resolved": {
2585
+ "derived_keys": {
2586
+ "key_a": null,
2587
+ "key_b": null
2588
+ },
2589
+ "detector": {
2590
+ "alpha": null,
2591
+ "context_width": 16,
2592
+ "deduplicate_contexts": true,
2593
+ "key_b_prf_key": null,
2594
+ "p_value_threshold": 0.01,
2595
+ "prf_key": "18446744073709551615",
2596
+ "type": "GumbelWatermarkDetector"
2597
+ },
2598
+ "watermark_config": {
2599
+ "algorithm": "gumbel",
2600
+ "allow_target_only_watermarking": false,
2601
+ "alpha": 0.1,
2602
+ "context_width": 16,
2603
+ "deduplicate_contexts": "all",
2604
+ "deduplicate_contexts_max_history": 8192,
2605
+ "prf": "philox"
2606
+ }
2607
+ },
2608
+ "trace": {
2609
+ "dedup_skips": 16,
2610
+ "key_b_effective": null,
2611
+ "key_b_routed": null,
2612
+ "partial_context_skips": 16,
2613
+ "routing_draws": 0
2614
+ }
2615
+ },
2616
+ "gumbel-philox-repeated-cw1": {
2617
+ "configuration": {
2618
+ "detection_key": "42",
2619
+ "fixture": {
2620
+ "dominant_bias": 52,
2621
+ "dominant_token": 3,
2622
+ "logit_denominator": 16,
2623
+ "logit_modulus": 131,
2624
+ "num_tokens": 48,
2625
+ "prompt": [],
2626
+ "vocabulary_size": 16
2627
+ },
2628
+ "key": "42",
2629
+ "prf": "philox",
2630
+ "prf_version": "philox4x32-10-v1",
2631
+ "scheme": "gumbel",
2632
+ "scheme_config": {
2633
+ "context_width": 1,
2634
+ "detection_alpha": 0.1,
2635
+ "detection_deduplicate_contexts": true,
2636
+ "generation_alpha": 0.1,
2637
+ "generation_deduplicate_contexts": "single_turn",
2638
+ "generation_deduplicate_contexts_max_history": 8192,
2639
+ "p_value_threshold": 0.01
2640
+ }
2641
+ },
2642
+ "detection": {
2643
+ "is_watermarked": true,
2644
+ "num_scored_tokens": 15,
2645
+ "p_value": 6.97501804959627e-05,
2646
+ "p_value_ratio": 0.00697501804959627,
2647
+ "score": 34.40948699058768
2648
+ },
2649
+ "generation": [
2650
+ 14,
2651
+ 3,
2652
+ 13,
2653
+ 2,
2654
+ 1,
2655
+ 8,
2656
+ 3,
2657
+ 3,
2658
+ 3,
2659
+ 10,
2660
+ 2,
2661
+ 2,
2662
+ 5,
2663
+ 15,
2664
+ 11,
2665
+ 3,
2666
+ 3,
2667
+ 6,
2668
+ 2,
2669
+ 5,
2670
+ 12,
2671
+ 11,
2672
+ 3,
2673
+ 3,
2674
+ 3,
2675
+ 6,
2676
+ 2,
2677
+ 5,
2678
+ 1,
2679
+ 3,
2680
+ 3,
2681
+ 3,
2682
+ 10,
2683
+ 6,
2684
+ 2,
2685
+ 5,
2686
+ 1,
2687
+ 3,
2688
+ 3,
2689
+ 3,
2690
+ 6,
2691
+ 13,
2692
+ 9,
2693
+ 4,
2694
+ 11,
2695
+ 3,
2696
+ 3,
2697
+ 3
2698
+ ],
2699
+ "resolved": {
2700
+ "derived_keys": {
2701
+ "key_a": null,
2702
+ "key_b": null
2703
+ },
2704
+ "detector": {
2705
+ "alpha": null,
2706
+ "context_width": 1,
2707
+ "deduplicate_contexts": true,
2708
+ "key_b_prf_key": null,
2709
+ "p_value_threshold": 0.01,
2710
+ "prf_key": "42",
2711
+ "type": "GumbelWatermarkDetector"
2712
+ },
2713
+ "watermark_config": {
2714
+ "algorithm": "gumbel",
2715
+ "allow_target_only_watermarking": false,
2716
+ "alpha": 0.1,
2717
+ "context_width": 1,
2718
+ "deduplicate_contexts": "single_turn",
2719
+ "deduplicate_contexts_max_history": 8192,
2720
+ "prf": "philox"
2721
+ }
2722
+ },
2723
+ "trace": {
2724
+ "dedup_skips": 33,
2725
+ "key_b_effective": null,
2726
+ "key_b_routed": null,
2727
+ "partial_context_skips": 0,
2728
+ "routing_draws": 0
2729
+ }
2730
+ },
2731
+ "gumbel-philox-repeated-cw4-all": {
2732
+ "configuration": {
2733
+ "detection_key": "42",
2734
+ "fixture": {
2735
+ "dominant_bias": 52,
2736
+ "dominant_token": 3,
2737
+ "logit_denominator": 16,
2738
+ "logit_modulus": 131,
2739
+ "num_tokens": 48,
2740
+ "prompt": [],
2741
+ "vocabulary_size": 16
2742
+ },
2743
+ "key": "42",
2744
+ "prf": "philox",
2745
+ "prf_version": "philox4x32-10-v1",
2746
+ "scheme": "gumbel",
2747
+ "scheme_config": {
2748
+ "context_width": 4,
2749
+ "detection_alpha": 0.1,
2750
+ "detection_deduplicate_contexts": true,
2751
+ "generation_alpha": 0.1,
2752
+ "generation_deduplicate_contexts": "all",
2753
+ "generation_deduplicate_contexts_max_history": 8192,
2754
+ "p_value_threshold": 0.01
2755
+ }
2756
+ },
2757
+ "detection": {
2758
+ "is_watermarked": true,
2759
+ "num_scored_tokens": 47,
2760
+ "p_value": 6.687298332875021e-08,
2761
+ "p_value_ratio": 6.687298332875021e-06,
2762
+ "score": 92.47607252164309
2763
+ },
2764
+ "generation": [
2765
+ 3,
2766
+ 3,
2767
+ 6,
2768
+ 2,
2769
+ 4,
2770
+ 1,
2771
+ 3,
2772
+ 3,
2773
+ 3,
2774
+ 10,
2775
+ 2,
2776
+ 2,
2777
+ 3,
2778
+ 8,
2779
+ 4,
2780
+ 3,
2781
+ 3,
2782
+ 6,
2783
+ 12,
2784
+ 5,
2785
+ 8,
2786
+ 4,
2787
+ 11,
2788
+ 10,
2789
+ 3,
2790
+ 6,
2791
+ 9,
2792
+ 5,
2793
+ 8,
2794
+ 11,
2795
+ 3,
2796
+ 3,
2797
+ 10,
2798
+ 6,
2799
+ 1,
2800
+ 12,
2801
+ 3,
2802
+ 3,
2803
+ 3,
2804
+ 3,
2805
+ 6,
2806
+ 9,
2807
+ 5,
2808
+ 5,
2809
+ 8,
2810
+ 0,
2811
+ 0,
2812
+ 3
2813
+ ],
2814
+ "resolved": {
2815
+ "derived_keys": {
2816
+ "key_a": null,
2817
+ "key_b": null
2818
+ },
2819
+ "detector": {
2820
+ "alpha": null,
2821
+ "context_width": 4,
2822
+ "deduplicate_contexts": true,
2823
+ "key_b_prf_key": null,
2824
+ "p_value_threshold": 0.01,
2825
+ "prf_key": "42",
2826
+ "type": "GumbelWatermarkDetector"
2827
+ },
2828
+ "watermark_config": {
2829
+ "algorithm": "gumbel",
2830
+ "allow_target_only_watermarking": false,
2831
+ "alpha": 0.1,
2832
+ "context_width": 4,
2833
+ "deduplicate_contexts": "all",
2834
+ "deduplicate_contexts_max_history": 8192,
2835
+ "prf": "philox"
2836
+ }
2837
+ },
2838
+ "trace": {
2839
+ "dedup_skips": 5,
2840
+ "key_b_effective": null,
2841
+ "key_b_routed": null,
2842
+ "partial_context_skips": 4,
2843
+ "routing_draws": 0
2844
+ }
2845
+ }
2846
+ },
2847
+ "schema_version": 3
2848
+}