红绿水印

红绿水印(Green-Red Watermarking)是当前最简单、最可实施的GenAI文本水印方案。本文从密钥生成、公式推导、检测算法、完整案例四个维度,帮你完全掌握这种方案的工作逻辑——这也是理解新一代高鲁棒性文本水印(如PRC、不可检测水印)的基础。

1. 红绿水印

1.1 从研究角度

  • 概念清晰:用"红绿灯"比喻,避免了复杂的密码学记号,是理解水印的最快入门。
  • 基础性:它是后续高阶方案(不可检测水印、伪随机纠错码水印)的逻辑基础。
  • 完整性:涵盖"密钥、生成、检测、评估"的全链路。

1.2 从产业角度

  • 可实施性强:无需修改模型架构,只在解码层干预,当前已被DeepMind SynthID等商业方案部分采用。
  • 成本低:计算开销最小(仅在生成每个token时做一次PRF计算和logits偏置)。
  • 可审计:逻辑透明,便于监管机构或第三方验证。

1.3 理解其局限,才能把握升级方向

  • 失真(会改变模型输出分布);
  • 抗攻击性较弱(同义词替换可破坏水印)。

后续的方案(如Gumbel、PRC)都在试图克服这些问题,学会红绿水印,你就能看懂为什么它们要这样做。

2. 关键概念讲解

2.1 PRF(gk, contextᵢ):伪随机函数是什么?

  • PRF:全称是 Pseudorandom Function(伪随机函数)。
  • 作用:它就像一个“带锁的随机数生成器”。只要输入相同的密钥(gk)上下文(contextᵢ),它就会输出完全相同的结果;如果输入不同,输出就像真随机数一样不可预测。
  • 在红绿水印里的作用
    • 它接收两个输入:
      • gk:水印的生成密钥,只有合法的模型所有者知道。
      • contextᵢ:生成第 i 个 token 时,前面已经生成的 k 个 token(即上下文)。
    • 它的输出 Gᵢ 是一个词汇表的子集,也就是我们说的“绿列表”。
    • 因为 PRF 是确定性的,所以只要密钥 gk 相同,对于相同的上下文,绿列表 Gᵢ 就完全相同。这是检测水印的关键。

2.2 Gᵢ 和 Rᵢ:红绿列表是什么?

  • Gᵢ:在第 i 个位置,根据 PRF 划分出的"绿列表",是词汇表 V 的一个子集。
  • Rᵢ:“红列表”,就是词汇表中不在绿列表里的所有 token,即 Rᵢ = V \ Gᵢ
  • 直观理解:在生成每个词之前,模型都会根据前面的上下文和密钥,临时决定"哪些词是’幸运词’(绿列表),哪些是’普通词’(红列表)"。

2.3 lᵢ(v):模型的 logits 是什么?

  • lᵢ(v):在第 i 个位置,模型对词汇表中每个 token v 输出的原始对数几率(logits)
  • 含义:它是一个未归一化的概率值,代表模型认为下一个词是 v 的"倾向性"。值越大,模型越倾向于生成这个词。
  • 例子:如果模型在"我今天去"之后,lᵢ("超市") = 5.2lᵢ("公园") = 3.1,说明模型更倾向于生成"超市"。

3. 生成密钥与PRF计算

3.1 gk(生成密钥)的来源与规范

gk 是人为规定/生成的密钥,但不是随便填个数字就行,需要遵循“安全密钥生成规范”,核心目的是确保密钥的“随机性”和“唯一性”——避免被攻击者猜到或破解。

3.1.1 谁来规定/生成gk?
  • 通常是水印方案的设计者/模型提供商(比如谷歌、OpenAI 这类公司,或研究人员);
  • 比如红绿水印的提出者(Kirchenbauer et al. 2023)在实验中,会自己生成 gk;如果是工业界落地(如谷歌 SynthID),gk 会由公司的安全团队按标准流程生成。
3.1.2 gk 的规定/生成规则(核心是“随机+足够长”)
  • 长度要求:必须足够长(通常 ≥128 位,工业界常用 256 位),比如 gk 可以是一串 256 位的二进制数(01 组合),或对应的十六进制字符串(如 0x7a9f...3d8b);
  • 随机性要求:必须是“ cryptographically secure random ”(密码学安全的随机数),不能用简单的“时间戳+随机数”生成(容易被预测),要通过专门的随机数生成器(如 Python 的 secrets 模块、OpenSSL 的随机数生成接口);
  • 格式要求:通常是字节串(byte string)或整数,具体格式由 PRF 函数的要求决定(比如 PRF 要求输入 32 字节的密钥,gk 就生成 32 字节的随机字节串)。
3.1.3 例子:gk 长什么样?
  • 256 位二进制 gk(简化版):10110010...01101001(共 256 个 0/1);
  • 对应的十六进制 gk(更易存储):0xb27f3d...69a8(64 个十六进制字符,1 个十六进制字符=4 位二进制);
  • 实际使用中,gk 会被存储为文件(如 .env 文件中的 CHATGPT_API_KEY 格式),或通过安全密钥管理系统(如 AWS KMS)存储。

3.2 PRF 如何计算 gk 和 context:固定算法+密钥绑定,结果完全确定

PRF(伪随机函数)是预先定义好的标准算法(不是随便设计的),输入“gk + context”后,会按固定步骤计算,输出唯一的结果(即绿列表 Gᵢ 的划分依据)。

3.2.1 第一步:明确 PRF 的具体算法(红绿水印常用的是 HMAC 类 PRF)

红绿水印的论文中,PRF 通常采用 HMAC(哈希消息认证码) 算法(如 HMAC-SHA256)——这是密码学中常用的“密钥相关哈希函数”,满足 PRF 的核心要求:相同输入必出相同输出,不同输入输出随机无规律。

其他常用的 PRF 算法还包括 AES-CBC-MAC、Blake2b 等,但红绿水印因实现简单,优先用 HMAC 类。

3.2.2 第二步:对 input 做预处理(gk + context 转为 PRF 能处理的格式)

PRF 的输入必须是“字节串”,所以需要把 context(前 k 个 token 的序列)转为字节串,步骤如下:

  • 假设 context 是 token 序列 [v₁, v₂, ..., vₖ](如 ["我", "今天", "去"]);
  • 先把每个 token 转为对应的编码(如 UTF-8 编码,“我”→0xe68891);
  • 再把所有 token 的编码拼接起来,得到 context 的字节串 ctx_bytes = b"\xe68891\xe4\xbb\x8a\xe5\xa4\xa9\xe5\x8e\xbb"
  • gk 本身已是字节串(如 32 字节的 b'\x7a\x9f...\x3d\x8b')。
3.2.3 第三步:PRF 计算的核心步骤(以 HMAC-SHA256 为例)

HMAC 的计算逻辑是“密钥+消息→哈希值”,具体公式(简化版):
PRF(gk,context)=HMAC-SHA256(gk,ctxbytes) \text{PRF}(gk, context) = \text{HMAC-SHA256}(gk, ctx_bytes) PRF(gk,context)=HMAC-SHA256(gk,ctxbytes)
详细步骤:

  1. 用 gk 对 HMAC 的内部密钥进行处理(按 HMAC 标准,将 gk 扩展为 64 字节,与固定常量异或);
  2. 把处理后的密钥与 ctx_bytes(context 的字节串)拼接,计算 SHA256 哈希值;
  3. 再用处理后的密钥与第一步的哈希值拼接,再次计算 SHA256 哈希值;
  4. 最终得到的 32 字节哈希值(如 0x8f3d...a729),就是 PRF 的输出。
3.2.4 第四步:将 PRF 输出转为绿列表 Gᵢ(红绿水印的关键映射)

PRF 输出的是哈希值(一串随机字节),需要将其映射为“词汇表 V 的子集”(即 Gᵢ),常用方法是:

  • 对词汇表 V 中的每个 token v,计算其哈希值 hash(v)(如 SHA256(v 的 UTF-8 编码));
  • 取 PRF 输出的前 n 位(如 1 位)作为“判定位”;
  • hash(v) 的前 n 位,与 PRF 的判定位做“异或运算”(XOR);
  • 若结果为 0,则 v 属于 Gᵢ(绿列表);若为 1,则属于 Rᵢ(红列表)。
3.2.5 具体例子(简化版):
  • 词汇表 V = {A, B, C, D},每个 token 的 UTF-8 编码:A→0x41,B→0x42,C→0x43,D→0x44
  • gk = 0xb27f...69a8(32 字节),context = [A, B](ctx_bytes = 0x4142);
  • PRF(gk, ctx_bytes) = HMAC-SHA256(gk, 0x4142) → 输出 32 字节哈希值 0x8f3d...a729
  • 取 PRF 输出的第 1 位(二进制):假设是 0
  • 对每个 token 计算:
    • A:hash(A)=SHA256(0x41) → 前 1 位=1 → 1 XOR 0 = 0 → 属于 Gᵢ;
    • B:hash(B)=SHA256(0x42) → 前 1 位=0 → 0 XOR 0 = 1 → 属于 Rᵢ;
    • C:hash©=SHA256(0x43) → 前 1 位=0 → 0 XOR 0 = 1 → 属于 Rᵢ;
    • D:hash(D)=SHA256(0x44) → 前 1 位=1 → 1 XOR 0 = 0 → 属于 Gᵢ;
  • 最终 Gᵢ = {A, D},Rᵢ = {B, C}。

3.3 核心要点

gk 的生成和 PRF 的计算是保证水印可靠的两大基石:

  1. gk 的来源:人为按"密码学安全标准"生成(足够长+足够随机),由水印设计者/模型提供商管理;
  2. PRF 的计算逻辑:算法固定(如 HMAC-SHA256),输入"gk+context",输出确定的绿列表 Gᵢ;
  3. 核心特点:相同 gk + 相同 context → 必然得到相同 Gᵢ,这正是嵌入和检测一致性的保证。

4. 生成阶段:如何嵌入水印

4.1 红绿划分公式

Gi=PRF(gk,contexti),Ri=V∖Gi G_i = \text{PRF}(gk, \text{context}_i), \quad R_i = V \setminus G_i Gi=PRF(gk,contexti),Ri=VGi

  • 含义
    • 对于第 i 个位置,使用 PRF 函数,根据密钥 gk 和前面的上下文 contextᵢ,生成一个绿列表 Gᵢ
    • 红列表 Rᵢ 就是词汇表 V 中所有不在 Gᵢ 里的词。
  • 为什么这么做?
    • 这样做可以让绿列表的划分依赖于上下文,而不是固定不变的。这使得水印更难被攻击者通过简单的统计分析破解。

4.2 偏置(Bias)公式

l~i(v)={li(v)+δ若 v∈Gili(v)若 v∈Ri \tilde{l}_i(v) = \begin{cases} l_i(v) + \delta & \text{若 } v \in G_i \\ l_i(v) & \text{若 } v \in R_i \end{cases} l~i(v)={li(v)+δli(v) vGi vRi

  • 含义
    • 对绿列表 Gᵢ 中的每个词 v,在其原始 logits lᵢ(v) 的基础上,加上一个正的偏置值 δ(比如 δ=0.5)。
    • 对红列表 Rᵢ 中的词,保持原始 logits 不变。
  • 效果
    • 加上偏置后,绿列表中词的 logits 变大了,模型在采样时,就会更倾向于选择绿列表中的词
    • 这就人为地提高了绿 token 在生成文本中的出现频率。

5. 检测阶段:如何验证水印

5.1 z 统计量公式

z=∣s∣G−γTTγ(1−γ) z = \frac{|s|_G - \gamma T}{\sqrt{T \gamma (1-\gamma)}} z=Tγ(1γ) sGγT
这个公式是整个水印检测的核心,我们把它拆开来看:

  • 分子部分:|s|_G - γT

    • |s|_G:在待检测文本 s 中,统计出来的绿 token 总数
    • γT:在没有水印的情况下,这段文本中绿 token 的期望数量
      • γ:无水印时,绿 token 出现的概率,因为 PRF 是伪随机的,所以 γ 理论上接近 0.5。
      • T:文本的总长度(token 数)。
    • 含义:这个差值代表了“实际绿 token 数量”与“随机情况下的期望数量”之间的偏差。如果水印存在,这个偏差会是一个很大的正数
  • 分母部分:√(T γ (1-γ))

    • 这是统计学中二项分布的标准差
    • 它衡量了在随机情况下,绿 token 数量 |s|_G 围绕其期望值 γT 波动的幅度。
  • 整体 z 值的含义

    • z 是一个标准化的偏差值,它告诉我们:实际观察到的绿 token 数量,比随机情况下的期望值“高出了多少个标准差”。
    • 如果 z 值很大(比如大于 4 或 5),就说明绿 token 数量的偏高,极不可能是随机巧合,而是由人为干预(水印)造成的。

5.2 检测判定规则

z>zα z > z_\alpha z>zα

  • z_α:是一个预先设定的阈值,它对应着统计学中的显著性水平 α(比如 α=0.001)。
  • 含义
    • 如果计算出的 z 值大于 z_α,我们就拒绝“这段文本是无水印的”这个零假设,判定它是带水印的
    • 这个阈值确保了假阳性率(把人类写的文本误判为带水印)被控制在极低的水平(如 0.1%)。

6. 案例

假设我们有一个词汇表 V = {A, B, C, D},密钥 gk,上下文 contextᵢ = "我"

  1. 生成阶段

    • PRF(gk, “我”) 输出绿列表 Gᵢ = {A, C},红列表 Rᵢ = {B, D}
    • 模型原始 logits:lᵢ(A)=2, lᵢ(B)=3, lᵢ(C)=1, lᵢ(D)=4
    • 加上偏置 δ=1 后:l̃ᵢ(A)=3, l̃ᵢ(B)=3, l̃ᵢ(C)=2, l̃ᵢ(D)=4
    • 模型从新的 logits 中采样,更可能选到绿列表中的 A 或 C。
  2. 检测阶段

    • 拿到一段文本 s = "A C A B",长度 T=4。
    • 用相同的 gk 和 PRF,逐个位置判断每个 token 是否为绿 token:A(绿), C(绿), A(绿), B(红)。
    • 统计 |s|_G = 3
    • 假设 γ=0.5,期望数量 γT = 2,标准差 √(4*0.5*0.5) = 1
    • 计算 z = (3 - 2) / 1 = 1。这个 z 值太小,不足以判定为水印。如果文本更长,比如有 100 个 token,其中 65 个是绿 token,z 值就会变得很大,从而被检测出来。

7. 属性评估

基于 SoK 论文的五大评估维度,红绿水印的现状如下:

属性 评估 详解
质量保持 ⭐⭐⭐ (低失真) 因为加偏置,会改变模型的输出分布,实证失真度约 0.01~0.05
低假阳性率 ⭐⭐⭐⭐⭐ (优秀) 通过 z 统计量和高显著性阈值控制,误判率可达 0.1% 以下
鲁棒性 ⭐⭐⭐ (中等) 抵御基础编辑(删节、改写)能力有限,对同义词替换很敏感
不可伪造性 ⭐⭐⭐⭐ (强) 攻击者无生成密钥时,难以伪造带水印文本
计算效率 ⭐⭐⭐⭐⭐ (极优) 仅需在生成每个 token 时做 PRF+偏置操作,开销极低

总体定位:一个"快速、可靠、但易被攻击者破坏"的早期实用方案。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐