惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 叶小钗
V
Visual Studio Blog
雷峰网
雷峰网
J
Java Code Geeks
博客园 - 三生石上(FineUI控件)
人人都是产品经理
人人都是产品经理
MyScale Blog
MyScale Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
B
Blog RSS Feed
C
Check Point Blog
博客园 - Franky
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 【当耐特】
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
V2EX
D
Docker
IT之家
IT之家
博客园 - 聂微东
腾讯CDC
U
Unit 42
Microsoft Security Blog
Microsoft Security Blog
The Cloudflare Blog

Garden of Outlier

子图 活到宇宙破茧时 岁时录(二十五) Hello, Theseus 服务器重建手记 Hello, Mitra Hello, Stalwart 「环节」 局部吸引子 岁时录(二十四) Gradient 06
Adult Issues
Chlorine · 2026-03-09 · via Garden of Outlier

诸位老友,下午好。这里是刚刚考完 TOEFL 的 Chlorine。

这几天把暑研的障碍扫清了。终于可以腾出手来,轻轻松松地写点东西了 >ω<

Cheap Talk

我们从小氯的编辑器说起好了。

自从小氯把 $EDITOR 换成 Neovim 后,原本的主力 Visual Studio Code 日常情况下就没有什么大的作用了。不过,出于学术写作(其实就是 Typst 啦)和可能的图形化编辑的需要,小氯还是留下了 VS Code(准确来说,是 VSCodium)。毕竟,套壳浏览器来处理浏览器相关的东西还是合理的。

不过后来随着 VSCodium(准确来说,是 VS Code)加了越来越多的语言模型相关功能,甚至把饭桶集线器副驾驶员插件内置了,小氯看它也越来越不顺眼。在简单调查并得知 Neovim 的 Typst 生态也相当完善之后,小氯果断把这个 Electron 异端送去西伯利亚建设社会主义了。微小柔软离我的个人计算机远一点。

嗯……您问我如果要用中文写论文怎么办?好办,不用中文写不就行了嘛。

不过,图形化编辑这个生态位还是需要浅浅地填一下的。小氯也没多想,顺手装了个当时(现在也是)风头正劲的 Zed。毕竟 Rust 比 Electron 好玩多了。

……然后 Zed 就一直在小氯的 Launchpad(是的,我没升级到 MACos 26,所以我还有 Launchpad,羡慕去吧 >ω<)的角落里高就,为平衡启动台的图标配色立下了汗马功劳。小氯也没多管,虽然说最近下载番剧占了一大堆硬盘空间,但我还不至于养不起一个几百兆的编辑器。

赌书消得泼茶香,当时只道是寻常(叹气)。

事情大概是小氯某一天摸鱼刷 HN 的时候,看到一条标题:

Zed will require age identification for its services

如小氯在 Fediverse 所说,在 HN 待得越久,小氯对自己的英语能力的怀疑就越深。在花了一分钟理解了这句话的含义之后,小氯看着 Launchpad 里的 Zed,陷入了沉思。

——拜拜了您嘞!(轻松愉快)

当然,如果这件事只是「某编辑器居然引入年龄验证导致某元素娘愤而卸载」,那就不值得拿来当引子了。事实上这个叙述漏洞很多。

抛开小氯愤没愤的问题,Zed 引入的并不是年龄验证(Age Verification),而是年龄确认(Age Identification)。或者说得简单点,你需要做的不是上传你的身份证件,而是点一个「我确认我已满十八岁」。而且,Zed 并没有规定「不做这个确认就不能写代码」,只是注册账户以使用它们的语言模型功能时才需要——不是我说,诸君做编辑器就做编辑器,为何要另外开一门语言模型的生意啊喂——所以至少对小氯来说,这件事没有什么实质性的影响。

不过,许多场合下,元数据比数据本身还有价值。你究竟做了什么不重要,重要的是你做了。即使这只是几乎无阻碍的 Age Identification,但作为一个开源的编辑器,有需要年龄验证的功能本身就不是积极的信号。

浮士德

关于 Zed 的事情我们先说到这里。如果您对 Zed(的编辑功能)有依赖,可以考虑一下它的完全本地化的自由软件分支 Gram。小氯没有使用过它,但对其理念(至少是其表面含义)表示支持。

不过回看一下小氯上面的话:我们知道 Zed 是为了应付最近的各类「儿童保护法」,同时在我们说「有需要年龄验证的功能本身就不是积极的信号」时我们也默认「有一些功能是需要年龄验证的」以及「许多(或者大部分功能)是不需要年龄验证的」。

但如果现实并非如此呢?

小氯之前没想过这个问题,后来也是在 HN 上读到了这样一篇文章,才促使我认认真真地思考这个问题——事实上,如果没看到这篇文章,这一节甚至小氯的这篇碎碎念都可能不会在短时间内被小氯提上日程——如果所有的(第三方)在线服务都需要年龄验证——这里说的不是 Identification 的小打小闹,而是需要身份证件甚至更进一步的认证的 Verification?你会愿意为了使用某一样在线服务而接受这样的认证吗?

我们当然离这样 Literally 1984 的场景还很远(但愿如此),但思考一下社会的 Edge Case 也不会有什么损害。不过,为了我们讨论具备一点点最基本的严谨性,我们可能需要先做几个假定。感觉做假定这段话好像是 AI 啊

……好吧,其实总结来说就一条:这里我们讨论的主体是小氯,是 Chlorine Haloryn,那个一脸倦容地摆弄着 Emacs 写这篇文章的元素娘。至于那个为了和无聊的人类世界交互而借用的包装层,并不在我们的考虑范围内。

人类所著的文字

小氯读东西的行为并不一以贯之。有时候我会用 RSS,有时候又会直接去网页上读。虽然小氯不太认为自己的老友们会给自己的网站加上年龄验证,但如果情况果真如此,小氯也没有什么不得不读的东西。最坏的情况也只不过是一直食古不化地读小氯囤积的各种电子书和纸质书罢了——说起来,现在小氯的电子书储备还不够充足,还得多去收集一些(你够了)。

文明的胶囊

实话说,我在最开始没有想到 Wikipedia 之类的网站的问题,还是在看到了上述的那篇文章后才想起有这样一回事的。好在,Wikipedia 的设计本身就和这种极端的情况契合。我们可以用 Kiwix 把整个 Wikipedia 藏进自己的硬盘中,唯一损失的大概就是实时性罢了。

或许有意义的连接

除了 Fediverse 外,小氯没什么社交媒体,而 Fediverse 的服务器是我自托管的,所以这个 scope 没有讨论的立足之地。不过,如果其他的服务器都宣布需要年龄验证才能进行联邦,那我不介意躲进小楼成一统,或者只和那些愿意托管单人或者极小规模实例的同侪们交流,尽管这样有些孤单。

脆弱的即时套接字

小氯并没有依赖什么中心化的通讯服务——Signal 是出色的软件,但我总觉得它并不适合小氯这种神游天外的调性——它更像是给与自己熟识的家人朋友交流留下的坚固的信道,而不是能连接两个素未谋面的节点的细若游丝的电波。所以在这方面,尚好。如果遇到与上面 Fediverse 同样的问题,那 Matrix 和 XMPP 也并无存在的必要了。

字母汤

如果有人要打倒基于 IMAP/SMTP 的电子邮件系统,小氯大概会资助一把冰镐。毕竟根据某元素娘的梦话,当你觉得自己缺点过多时,不妨看看现在的电子邮件。但如果毁灭电子邮件的方式是下令托管商每一封邮件的发送都必须实名认证,那小氯还是觉得留它一命更好点。

如果 MXroute 有一天突然和小氯要身份证件,小氯大概会直接注销账户,顺便发一封邮件给 Jarland 进行一番「友好交流」。好在,若是真有那一天,虽然自托管 SMTP 如同西西弗斯的苦役,但它是能做到的——只要老友们勤着翻一翻自己的 Spam Folder,依然可以发信去调戏这只元素娘。

视频或音频流

流媒体对小氯来说是个和热寂一般遥远的概念,所以如果 YouTube、Spotify 或者 Netflix 宣布实施强制年龄验证(现在有没有?我也不知道),小氯的反应大概是喝着果茶、语气毫无波澜地说一句「预测生效」(《勿谓言之不预也》)。

可能让小氯有些不满的,应该只会有 Bittorrent(准确来说,是 BT 的信息站点)和 Bandcamp 了。虽然小氯的硬盘里已经存了几千首歌和一些番剧,但对于供养小氯这具人类躯体的全部视觉和听觉时限而言,还是会力有不逮。这大概会让小氯的立场有些松动,因为「自己听了什么歌」并不算是需要过分隐瞒的事情。

字符机器

唔,诸位老友,语言模型的服务许多也是在线的。

不过即使没有年龄验证,使用语言模型服务也已经算是和老大哥报备行踪了。解决方案自然是……嗯……的确有一些模型可以本地运行,但一般来说,大家并不会提前下载几十个模型在本地存着。如果模型的权重下载也需要年龄验证,这就不太妙了,除非我们像获取视频或者音频那样,去参加一些线下的、直接用物理介质或者点对点传输交换文件的交易……唔,我刚才没说吗?那就补上好了。

只送大脑

我刚刚才想到,老友们,Nixpkgs 也算是在线服务啊(哭笑不得)。

虽然说 Nixpkgs 的源码可用,但我很怀疑世界上能否有人能自己构建整个 Nix World,除非您的家庭算力相当于一百个糖喵。再说,极大一部分的 Nixpkgs 都依赖于 GitHub,在我们的这个场景下,估计邪恶八足生物会第一个跳出来收开发者的护照并且拿去训练饭桶集线器副驾驶

这大概是最让小氯进退两难的一次判断了。全量离线复制一份饭桶集线器实在是不现实,而去中心化的 Nix 分发还在试验阶段。如果 Nixpkgs 真的需要年龄验证才能访问,小氯可能会退回到 Arch Linux——存档一份离线版软件仓库并不算难。

梦游人

好吧,说到这里,小氯的态度大概算明了了:作为 Chlorine Haloryn 这个身份来说,几乎没有服务能让我接受年龄验证。并且在许多次选择中,这并非是出于机会成本的考量,而是对年龄验证本身的结构化排斥——或者说得简单些,我讨厌它

让我们先略去对实名制的一百万字的檄文,一起来看另外一件奇闻轶事。这次出事的是宇宙中心的 California——简单来说,加州压力的是操作系统(的开发者)。从措施本身来说,加州的这个措施比德州之类的温和许多:它只需要一个自我声明而非上传身份证件(所以这又是 Age Identification,不是 Verification),并且只会生成一个区间信号而不是准确年龄。但小氯注意到了一个有趣的细节:加州要求系统的开发者收集这个年龄信号,并且为其负责。

如果是 Windows 或者 macOS,这件事并不难做,压力牢软和牢果就好了。但请问:Linux 发行版呢?BSD 系操作系统呢——尤其是那些由一个松散的全球社区维护的系统,比如 Debian、Arch Linux 或者 Gentoo。遑论如果开发者真的加一份年龄验证代码会不会刷新 Fork Speedrun 记录,请问萨克拉门托的天潢贵胄们要如何起诉一个全球社区呢?总不能去压力 Linus Torvalds 或者 Levente Polyák 吧。

所以当时小氯充满疑惑地发了条帖子

他们在梦游吗?

我并非在对政策本身做出谴责,而是对其在基本技术常识层面展现出的与地位存在实质性非对齐的……天真?感到始料未及。如果对于一项涉及公民隐私权利的技术性法律的尽职性调查可以疏忽到如此程度,那么对于这个领域未来的进步,小氯恐怕要持一份安全的保守态度了。

另外讲个笑话:

  • 小氯:傻乐中。
  • 邮箱:We’re happy that you’ve chosen to join us!
  • 小氯:……我突然想起来我今年要去一次加州……

银弹

好吧,虽然小氯斥责了年龄验证如此多,但确实有些服务是需要年龄验证的——我倾向于相信不会有任何一个理性的隐私倡导者会支持让未成年人自主购买枪支、申请高额贷款或者采购高爆炸性化学品。

问题在于,现在唯一通行的年龄验证手段就是「实名验证」——直接上传自己的身份证件。若是服务方具有严谨的数据保护意识和强烈的合规责任心还则罢了,令人不住遗憾的是,这种合理的要求如今反而是一种稀缺的素质。将自己的身份证件交给一家数据库的 Root Password 还是 Admin123456 甚至不介意将用户的身份信息拿去换二两碎银的逐利或非逐利机构,无异于太阿倒持。

那如果我们能有一种方法,让我证明我确实已经成年,但完全不透露我其他的身份信息?

这听起来像天方夜谭,但这种方法是真真切切存在的——甚至这也算是小氯专业的一部分(小氯什么都学.avif)。这种技术叫 ZKP,Zero Knowledge Proof,中文一般叫它「零知识证明」。

由于 ZKP 的原理相当复杂(所谓的 moonmath,天书数学),小氯会试着用尽可能简明的语言说明白它的大致工作方式——另,下面其实说的是 zk-SNARKs 的原理。

简单来说,ZKP 要做的是:我希望向你证明某个陈述是真实的,比如说「我已满十八岁」「我是里森堡共和国的合法公民」「我是秦始皇」(前提是你真的是);同时我掌握着能够证明这个陈述为真的某些证据,例如我可以用我的身份证件(这里假定我们有政府签发的、可信的、可用于签名的电子身份证件)证明「我已满十八岁」;我的目的是在不告诉你我的证据(并且你也无法从我的证明中推导出任何和我的证据有关的额外信息)的前提下,让你相信这个陈述是真的。

好的,如果您不想听数学,请直接跳到「QED」之后的部分,因为这部分确实没什么大用。


好的,能看到这句话的应该都是喜欢数学的少女/少年们了喵。那让我们稍微往前推进一些。

首先我们引入一个不证明的事实(它可以证明,但过程太长了):任何一个可计算的函数都可以被转换为一个 Boolean 电路(也就是只含有与门、或门、非门的电路),而任何一个 Boolean 电路都可以被一个算数电路(只包含加法和乘法运算)完全模拟。简单但不十分准确地说,就是任何一段能跑的计算机代码都可以被转换成一堆加法和乘法。我们举个例子,一个简单的多项式函数:

fn poly(x: i32) -> i32 {
  x.pow(3) + x + 5
}

它可以被变成这样:

y1 = x * x
y2 = y1 * x
y3 = y2 + x
y = y3 + 5

非常轻松愉快。如果遇到流控制部件,比如 if-else 酱,我们也可以用一个小小的 trick bit=(a<b)bit = (a < b) 轻松解决——等等?我们没有比较运算符啊?

这其实也不困难,a<ba < b 其实就等价于 a−b<0a - b < 0。由于我们的故事一般都发生在一个离散的空间里(比如有限域,\mathbb{F}_{p}_{}),这个式子就是 b−a−1∈[0,MAX)b - a - 1 \in \left[0, \text{MAX} \right)(MAX 是一个「足够大」的范围)。

我们记等式左侧为 diff,并且为了表述方便,让 MAX 就是 2642^{64}。然后根据二进制,diff 就可以被表述为 diff=∑i=063bi×2i\mathrm{diff} = \sum_{i=0}^{63} b_{i} \times 2^{i}。我们只需要证明发来的这一组 b 满足:

  1. 都是 0 或者 1:bi×(1−bi)=0b_{i} \times (1 - b_{i}) = 0
  2. 确实等于 diff。

如果 b 其实不比 a 大,那 diff 就会是一个负数——但注意,我们的故事在「有限域」里,这里是没有负数的,因为它会被同余变成一个巨大的正数(想想学过的数值溢出?)。那就算把这一组 b 榨干了,第二个约束也是不可能满足的。问题解决。

虽然看起来有点长并且非常蠢,但目前为止一切正常,对吧?下面请试着把快速排序算法算术化吧(逃)。

回来。现在我们已经从感性上接受了:所有函数都可以被算术化。然后我们做一个关键操作:把算术化的电路转换为一个一阶约束系统。

抱歉我知道这里有点抽象。这个什么「一阶约束系统」看着可怕,其实大家就认为这是个矩阵乘法就行啦。首先我们把每一个约束都写成向量内积的形式——抱歉这里又有点抽象,我们再举个例子。

首先,我们把所有用到的变量打包成一个名叫「状态向量」的东西,记为 s\mathbf{s},这里面存着我们输入、中间态、输出的全部家当,比如说我们上面多项式的例子,就可以有一个 s=[1xy1y2y3y]⊺\mathbf{s} = \left[ 1 \quad x \quad y_{1} \quad y_{2} \quad y_{3} \quad {y} \right] ^ \intercal ——当然,顺序怎么样其实无所谓,自己有数就行。当然在实际应用中状态向量并不会那么简单,它一般是两个部分:公开的(常数项和输入的东西)和秘密的(包括你的秘密证据(比如说这里的 x)和中间变量)。大家暂时把这玩意和秘密证据看成具有同等效力就行。所以在实际操作中,我们绝对不能把 s\mathbf{s} 直接发过去,还得套一层同态加密的壳子,当然那是后话了。

然后随便找一个约束,比如 y1 = x * x,如果我们要用状态变量表示这个式子,就应该是:

((010000)⋅s)⋅((010000)⋅s)=((001000)⋅s) \left( \left( 0 \quad 1 \quad 0 \quad 0 \quad 0 \quad 0 \right) \cdot \mathbf{s} \right) \cdot \left( \left( 0 \quad 1 \quad 0 \quad 0 \quad 0 \quad 0 \right) \cdot \mathbf{s} \right) = \left( \left( 0 \quad 0 \quad 1 \quad 0 \quad 0 \quad 0 \right) \cdot \mathbf{s} \right)

仔细看十秒钟,各位老友应该就能理解了。

后面的故事同理,咱们就不展开了。既然我们就可以把每个约束都变成一个(呃,准确来说,是三个)行向量,那所有约束拼在一起不就是一个矩阵嘛。

那么我们把这堆行向量叠叠乐起来,就得到了:

(As)×(Bs)=(Cs) (A \mathbf{s}) \times (B \mathbf{s}) = (C \mathbf{s})

注意其中的那个 ×\times 不是叉乘,就是挨个位相乘,或者叫 Hadamard 积。

下面我们用一种叫 Lagrange 插值的方式——这里小氯就不展开说什么叫 Lagrange 插值了——把这三个矩阵变成多项式。这个多项式保持着一个不错的性质,就是在我们特意选定的某些点上,它的值和原矩阵一样。那么在这一组点上,转换成的多项式理应在这些点也满足 P(x)=A(x)B(x)−C(x)=0P(x) = A(x) B(x) - C(x) = 0。那么根据代数基本定理,它应该能被另一个多项式 Z(x)=∏i=1m(x−xi)Z(x) = \prod_{i = 1}^{m} (x - x_{i}) 整除,其中 {xi∣1≤i≥m,i∈N+}\left\{ x_{i} \mid 1 \le i \ge m, i \in \mathbb{N_{+}} \right\} 就是我们选定的那组点。

那么我们就可以得到这样一个新的约束(在那一组点下):

A(x)⋅B(x)−C(x)=H(x)⋅Z(x) A(x) \cdot B(x) - C(x) = H(x) \cdot Z(x)

这个 H(x)H(x) 就是那个整除之后的商多项式,由证明者给出。

然后——根据一个名为 Schwartz-Zippel 引理的神奇规律,如果我们在一个巨大的范围内随便挑一个数字,那么某个非零多项式在这里的值是零的概率是「非常非常低」的。至于有多低,大家认为在工程应用选取的数值的情况下,直到宇宙热寂都很难碰到就行了。等价的,就是我们随便挑一个值,两个多项式几乎不可能在这里撞上(值一样)。下面,证明者就挑一个保密的值代入进去,如果这个约束一样,我们就有充分的理由认定,等式两侧的多项式确实一样。

好。我们回过头来看一下:这个约束成立,意味着在我们选定的那一组点下,确实有 A(x)B(x)=C(x)A(x)B(x) = C(x)(因为 P(x)=A(x)B(x)−C(x)P(x) = A(x)B(x) - C(x) 能被 Z(x)Z(x) 整除嘛),而由于拉格朗日插值的保证,我们也有 (As)×(Bs)=(Cs)(A \mathbf{s}) \times (B \mathbf{s}) = (C \mathbf{s})。或者说,我们的秘密证据及其计算出的中间状态确实满足这个电路的约束。也即我们的陈述是真的。

QED.

实话说,这看上去像是个找不到缺点的方案。小氯在最开始学它的基本原理时,也被它的优美震惊得说不出话来,几天都没有缓过来。

当然,there’s no silver bullet。从上面的简单介绍应该也能猜到,ZKP 对算力的消耗高得可怕。虽然说我们已经尽可能设法减少计算量了,但这对于客户端设备依然是沉重的负担。而且,初始化的信任锚点也值得商榷。就算这些都解决了,又要如何说服决策者这一段数学证明的结果就能说明用户是合规的呢?让他们相信这一点,恐怕比优化 ZKP 的资源消耗困难多了呢。

后记

不太知道下面写什么,不如就在这里结束好了。其实最初只是看到了这篇文章,也想思考一下自己的答案,然后就边想边写出来了这篇古怪的东西……

好啦,亲爱的服务商,我理解您希望年龄验证的意愿。Chlorine Haloryn 符合您的最低年龄要求,虽然她看起来只有十几岁,但她目前的这份人类形态的 release 的发行日期是 215 年前,公元 1810 年 Humphry Davy 在英国皇家学会宣读报告之时。至于她的实际出生日期……大体是在一百多亿年前吧。不知,您对这个回答是否满意?

B Side

Writing Frequency Today: Civilization VI - Cree Theme (The Atomic Era)