zkSNARKs 合约库「输入假名」漏洞致众多混币项目爆雷

ERC20智能合约的approve千万别这样写 作者:安比(SECBIT)实验室 最近智能合约安全事件频发,从BEC到SMT,从HXG到FXE等,最近这几个智能合约出的问题,大都是由于整数溢出漏洞导致的。大家对整数溢出是不是都杯弓蛇影了?我们是不是应该在所有的地方都加上安全检查,确保我们的代码没有问题呢?可是这样真的好吗? 我们先来看看这段代码: function approve(address _spender, uint _amou... 阅读详情

本文作者:p0n1(安比实验室)

大量零知识证明项目由于错误地使用了某个 zkSNARKs 合约库,引入「输入假名 (Input Aliasing) 」漏洞,可导致伪造证明、双花、重放等攻击行为发生,且攻击成本极低。众多以太坊社区开源项目受影响,其中包括三大最常用的 zkSNARKs 零知开发库 snarkjs、ethsnarks、ZoKrates,以及近期大热的三个混币(匿名转账)应用 hopper、Heiswap、Miximus。这是一场由 Solidity 语言之父 Chris 两年前随手贴的一段代码而引发的血案。

双花漏洞:最初暴露的问题

semaphore 是一个使用零知识证明技术的匿名信号系统,该项目由著名开发者 barryWhiteHat 此前的混币项目演化而来。

俄罗斯开发者 poma 最先指出该项目可能存在双花漏洞[1]。
在这里插入图片描述
问题出在第 83 行代码[2],请仔细看。在这里插入图片描述
该函数需要调用者构造一个零知识证明,证明自己可从合约中提走钱。为了防止「双花」发生,该函数还读取「废弃列表」,检查该证明的一个指定元素是否被标记过。如果该证明在废弃列表中,则合约判定校验不通过,调用者无法提走钱。开发者认为,这样一来相同的证明就无法被重复提交获利,认为此举可以有效防范双花或重放攻击。

然而事与愿违,这里忽视了一个致命问题。攻击者可根据已成功提交的证明,利用「输入假名」漏洞,对原输入稍加修改便能迅速「伪造证明」,顺利通过合约第 82 行的零知识证明校验,并绕过第 83 行的防双花检查。

该问题最早可追溯到 2017 年,由 Christian Reitwiessner 大神,也就是 Solidity 语言的发明者,提供的 zkSNARKs 合约密码学实现示例[3]。其后,几乎以太坊上所有使用 zkSNARKs 技术的合约,都照用了该实现。因此都可能遭受以下流程的攻击。
在这里插入图片描述

混币应用:该安全问题的重灾区

零知识证明技术在以太坊上最早和最广泛的应用场景是混币合约,或匿名转账、隐私交易。由于以太坊本身不支持匿名交易,而社区对于隐私保护的呼声越来越强烈,因此涌现出不少热门项目。这里以混币合约的应用场景为例,介绍「输入假名」漏洞对零知项目的安全威胁。

混币合约或匿名转账涉及两个要点:

  1. 证明自己有一笔钱
  2. 证明这笔钱没有花过

为了方便理解,这里简单描述一下流程:

  1. A 要花一笔钱。
  2. A 要证明自己拥有这笔钱。A 出示一个 zkproof,证明自己知道一个 hash (HashA) 的 preimage,且这个 hash 在以 root 为标志的 tree 的叶子上,且证明这个 preimage 的另一种 hash 是 HashB。其中 HashA 是 witness,HashB 是 public statement。由于 A 无需暴露 HashA,所以是匿名的。
  3. 合约校验 zkproof,并检查 HashB 是否在废弃列表中。若不在,则意味着这笔钱未花过,可以花(允许 A 的此次调用)。
  4. 如果可以花,合约需要把 HashB 放入废弃列表中,标明以 HashB 为代表的钱已经被花过,不能再次花了。

上面代码中的第 82 行 verifyProof(a, b, c, input) 用来证明这笔钱的合法性,input[] 是 public statement,即公共参数。第 83 行通过 require(nullifiers_set[input[1]] == false) 校验这笔钱是否被花过。

很多 zkSNARKs 合约尤其是混币合约,核心逻辑都与第 82 行和 83 行类似,因此都存在同样的安全问题,可利用「输入假名」漏洞进行攻击。

漏洞解析:一笔钱如何匿名地重复花 5 次?

上面 verifyProof(a, b, c, input) 函数的作用是根据传入的数值在椭圆曲线上进行计算校验,核心用到了名为 scalar_mul() 的函数,实现了椭圆曲线上的标量乘法[4]。

 /// @return the product of a point on G1 and a scalar, i.e.
    /// p == p.scalar_mul(1) and p.add(p) == p.scalar_mul(2) for all points p.
    function scalar_mul(G1Point point, uint s) internal returns (G1Point r) {
        uint[3] memory input;
        input[0] = p.X;
        input[1] = p.Y;
        input[2] = s;
        bool success;
        assembly {
            success := call(sub(gas, 2000), 7, 0, input, 0x80, r, 0x60)
            // Use "invalid" to make gas estimation work
            switch success case 0 { invalid() }
        }
        require (success);
    }

我们知道以太坊内置了多个预编译合约,进行椭圆曲线上的密码学运算,降低 zkSNARKs 验证在链上的 Gas 消耗。函数 scalar_mul() 的实现则调用了以太坊预编译 7 号合约,根据 EIP 196 实现了椭圆曲线 alt_bn128 上的标量乘法[5]。下图为黄皮书中对该操作的定义,我们常称之为 ECMUL 或 ecc_mul。
在这里插入图片描述
密码学中,椭圆曲线的 {x,y} 的值域是一个基于 mod p 的有限域,这个有限域称之为 Zp 或 Fp。也就是说,一个椭圆曲线上的一个点 {x,y} 中的 x,y 是 Fp 中的值。一条椭圆曲线上的某些点构成一个较大的循环群,这些点的个数称之为群的阶,记为q。基于椭圆曲线的加密就在这个循环群中进行。如果这个循环群的阶数(q)为质数,那么加密就可以在 mod q 的有限域中进行,该有限域记作 Fq。

一般选取较大的循环群作为加密计算的基础。在循环群中,任意选定一个非无穷远点作为生成元 G(通常这个群的阶q是个大质数,那么任选一个非零点都是等价的),其他所有的点都可以通过 G+G+… 产生出来。这个群里的元素个数为 q,也即一共有 q 个点,那么我们可以用 0,1,2,3,…q-1 来编号每一个点。在这里第 0 个点是无穷远点,点1 就是刚才提到的那个 G,也叫做基点。点2 就是 G+G,点3 就是 G+G+G。

于是当要表示一个点的时候,我们有两种方式。第一种是给出这个点的坐标 {x,y},这里 x,y 属于Fp。第二种方式是用 n*G 的方式给出,由于 G 是公开的,于是只要给出 n 就行了。n 属于 Fq。

看一下 scalar_mul(G1Point point, uint s) 函数签名,以 point 为生成元,计算 point+point+…+point,一共 n 个 point 相加。这属于使用上面第二种方法表示循环群中的一个点。

在 Solidity 智能合约实现中需要使用 uint256 类型来编码 Fq,但 uint256 类型的最大值是大于q 值,那么 会出现这样一种情况:在 uint256 中有多个数 经过 mod 运算之后都会对应到同一个 Fq中的值。比如 s 和 s + q 表示的其实是同一个点,即第s个点。这是因为在循环群中点q 其实等价于 点0(每个点分别对应 0,1,2,3,…q-1)。同理,s + 2q 等均对应到点s 。我们把可以输入多个大整数会对应到同一个 Fq中的值 这一现象称作「输入假名」,即这些数互为假名。

以太坊 7 号合约实现的椭圆曲线是 y^2 = ax^3+bx+c。p 和 q 分别如下。
在这里插入图片描述
这里的 q 值即上文中提到的群的阶数。那么在 uint256 类型范围内,共有 uint256_max / q 个,算下来也就是最多会有 5 个整数代表同一个点( 5 个「输入假名」)。

这意味着什么呢?让我们回顾上面调用 scalar_mul(G1Point point, uint s) 的 verifyProof(a, b, c, input) 函数,input[] 数组里的每个元素实际就是 s。对于每个 s,在 uint256 数据类型范围内,会最多存在其他 4 个值,传入后计算结果与原值一致。

因此,当用户向合约出示零知识证明进行提现后,合约会把 input[1] (也就是某个 s)放入作废列表。用户(或其他攻击者)还可以使用另外 4 个值再次进行证明提交。而这 4 个值之前并没有被列入「废弃列表」,因此“伪造”的证明可以顺利通过校验,利用 5 个「输入假名」一笔钱可以被重复花 5 次,而且攻击成本非常低!

还有更多受影响的项目

存在问题的远远不止 semaphore 一个。其他很多以太坊混币项目以及 zkSNARKs 项目都存在同样的允许「输入假名」的问题。

这当中,影响最大的要数几个大名鼎鼎的 zkSNARKs 库或框架项目,包括 snarkjs、ethsnarks、ZoKrates 等。许多应用项目会直接引用或参考他们的代码进行开发,从而埋下安全隐患。因此,上述三个项目迅速进行了安全修复更新。另外,多个利用了 zkSNARKs 技术的知名混币项目,如 hopper、Heiswap、Miximus 也立刻进行了同步修复。这些项目在社区热度都十分高,其中 Heiswap 更是被人们称为 「Vitalik 最喜爱的项目」。

「输入假名」漏洞的解决方案

事实上,所有使用了该 zkSNARKs 密码学合约库的项目都应该立即开展自查,评估是否受影响。那么应该如何修复这个问题?

所幸的是,修复很简单。仅需在验证函数中添加对输入参数大小的校验,强制要求 input 值小于上面提到的 q 值。即严禁「输入假名」,杜绝使用多个数表示同一个点。
在这里插入图片描述

暴露的深层问题值得反思

该「输入假名」导致的安全漏洞值得社区认真反思。我们再回顾一下整个故事。2017 年 Christian 在 Gist 网站贴出了自己的 zkSNARKs 合约计算实现。作为计算库,我们可以认为他的实现并没有安全问题,没有违反任何密码学常识,完美地完成了在合约中进行证明验证的工作。事实上,作为 Solidity 语言的发明者,Christian 在这里当然不会犯任何低级错误。而两年后的今天,这段代码却引发了如此的安全风波。两年多的时间内,可能有无数同行和专家看过或使用过这段只有两百多行的代码,却没有发现任何问题。

核心问题出在哪里?可能出在底层库的实现者和库的使用者双方间对于程序接口的理解出现了偏差。换句话说:底层库的实现者对于应用开发者的不当使用方式欠缺考虑;而上层应用开发者没有在使用中没有深入理解底层实现原理和注意事项,进行了错误的安全假设。

所幸的是,目前常见的 zkSNARKs 合约库都火速进行了更新,从底层库层面杜绝「输入假名」。安比(SECBIT)实验室认为,底层库的更新诚然能够很大程度上消除掉后续使用者的安全隐患,但若该问题的严重性没有得到广泛地宣传和传播,依旧会有开发者不幸使用到错误版本的代码,或者是根据错误的教程进行开发(就像因为整数溢出而归零的那些 Token 一样),从而埋下安全隐患。

「输入假名」漏洞不禁让我们回想起此前频繁曝出的「整数溢出」漏洞。二者相似之处颇多:都是源于大量开发者的错误假设;都与 Solidity 里的 uint256 类型有关;波及面都十分广;网络上也都流传着很多存在隐患的教程代码或者库合约。但显然「输入假名」漏洞显然更难检测,潜伏时间更长,需要的背景知识更多(涉及到复杂的椭圆曲线和密码学理论)。安比(SECBIT)实验室认为,随着 zkSNARKs、零知识证明应用、隐私技术的兴起,社区会涌现出更多的新应用,而背后暗藏的更多安全威胁可能会进一步暴露出来。希望这波新技术浪潮中,社区能充分吸收以往的惨痛教训,重视安全问题。

Reference

亚瑟王的「随机」挑战:从交互到非交互式零知识证明——探索零知识证明系列(四) 本文作者:郭宇 本文已更新至Github https://github.com/sec-bit/learning-zkp/blob/master/zkp-intro/4/zkp-rom.md “Challenges are at times an indication of Lord's trust in you.” 挑战,有时是上天信任你的一种表现。― D. Todd Christ... 阅读详情

相关推荐

零知识证明学习资源汇总

摘要:本文收集整理了关于零知识证明的一些学习资料,希望能对大家有所帮助。

SECBIT区块链安全实验室 3693

zk-snark的算法详解

前言 了解零知识证明的读者,可能都拜读过V神的文章,整个系列由浅入深,很有条理,相对其他文章更容易理解一下。其实V神讲解的算法是PGHR13算法的整体步骤,此算法也被应用于知名项目Zcash中,现在,就让我们去一起探究,在实际项目中,PGHR13算法是具体的什么步骤呢? PGHR13 在Zcash的Sapling版本升级之前,其采用的零知识证明算法的主体就是PGHR13,并因为效率和安全问题,做了...

weixin_43179764的博客 2914

零知识证明 Learn by Coding:libsnark 入门篇

本文作者:p0n1@安比实验室 libsnark 是目前实现 zk-SNARKs 电路最重要的框架,在众多私密交易或隐私计算相关项目间广泛应用,其中最著名当然要数 Zcash。Zcash 在 Sapling 版本升级前一直使用 libsnark 来实现电路(之后才替换为 bellman)。毫不夸张地说,libsnark 支撑并促进了 zk-SNARKs 技术的首次大规模应用,填补了零知识证明技术从...

SECBIT区块链安全实验室 2918

zk-SNARKs中input和witness size的权衡

主要来源 https://blog.ethereum.org/2016/12/05/zksnarks-in-a-nutshell/ 中“Tradeoff between Input and Witness Size”段落 论文GGPR12中,生成的proof只有7个elements of a group. Verifier主要需要计算pairing等式的成立(如 W := E(w(s)),W’ :...

mutourend2010@gmail.com 485

区块链之零知识证明(zk-SNARK从小白到明白)

零知识证明:从小白到明白 如今,知识快餐业发达,区块链这么火的领域自然不会落下。经过一轮轮扫盲,共识、工作量证明、闪电网络等等概念对普罗大众已不再陌生,甚至各种解构、比喻、引申,将术语炒得比本义还玄乎。然而,如果不理解甚至没听说过零知识证明,那你基本还属于区块链小白。 之所以这么说,原因有二。其一, 零知识证明是代数数论、抽象代数等数学理论的综合应用,与闪电网络一类的精巧设计不同,属于硬技术。...

跨链技术践行者 2万+

浅谈零知识证明之二:简短无交互证明(SNARK

本文作者东泽,来自安比技术社区的小伙伴,目前就读于斯坦福大学,研究方向密码学,本系列文章来源于作者在斯坦福著名的课程《CS 251: Cryptocurrencies and blockchain technologies》上的学习笔记,该课程授课老师是密码学大拿 Dan Boneh。 上一期文章发表之后,非常惊讶有那么多小伙伴读完了表示喜欢。那么我们接着这期继续吧!这次,我们专注的聊一聊SNAR...

SECBIT区块链安全实验室 2599

云中「秘密」:构建非交互式零知识证明---探索零知识证明系列(五)

本文作者:郭宇 Once exposed, a secret loses all its power. 一旦泄露,秘密就失去了全部威力 ― Ann Aguirre 这已经是本系列的第五篇文章了,这一篇继续深入非交互式零知识证明。 本文约 12,000 字。 系列一:初识「零知识」与「证明」 系列二:理解「模拟」 系列三:寻找「知识」 系列四:随机「挑战」 提纲 CRS 的前世今生 哈密尔...

SECBIT区块链安全实验室 2355

智能合约开发必读:ERC20 Token合约你可能不知道的坑

前不久,轰动一时的BEC事件在圈和链圈掀起了不小的反响,智能合约安全一度成为焦点话题。 通过一个小小的整数溢出漏洞,黑客盗取了巨量的BEC token,迫使交易所不得不暂时停止交易。一时间BEC价格呈现断崖式下跌。随后,SMT token 的智能合约也因为相同的问题遭到了攻击。 两次事件都给项目发行方和token持有者造成了巨额的损失。 据统计,截止2018年5月12日为止,以太坊上部署的...

SECBIT区块链安全实验室 2108

last-winner-airdrop

Last Winner 的最后赢家 - 智能合约超大规模黑客攻击手法曝光 作者:安比(SECBIT)实验室 & AnChain.ai 安比(SECBIT)实验室创始人郭宇:2009年,中本聪创造了一个虚拟的去中心化新世界。这仿佛是一片流着奶和蜜糖的应许之地,人们欢呼雀跃,蜂拥而至。但与所有的生态系统一样,新世界有生命,就有捕食者。有交易者,就有黑客。区块链上的应用在进化,攻击者也...

SECBIT区块链安全实验室 1873

构造形式化证明,解决智能合约安全问题——你的合约亟待证明

安比(SECBIT)实验室与 Consensys 中国、轻信科技等团队联手,在智能合约安全的形式化证明领域展开深度合作。 智能合约安全问题始终是萦绕在数字货各个项目方、开发者和投资者心头的一颗定时炸弹。越来越多的安全团队积极参与,试图通过更完备手段来解决合约安全问题。安比(SECBIT)实验室认为,形式化验证与传统的“测试+审计”方式相结合,将会是保证智能合约安全强有力的手段。 7月7日...

SECBIT区块链安全实验室 1787

一种利用 etherscan.io 缺陷的智能合约蜜罐正悄然流行

安比(SECBIT)实验室近期发出预警,一种新型蜜罐(诈骗)合约正在泛滥,利用区块链浏览器的相关局限,设置陷阱欺骗游戏参与者,且诈骗目标多为具备一定区块链专业素养的人员。据安比(SECBIT)实验室统计数据显示,同类合约的数量高达48个,其中一个合约部署于 3 天前,已有玩家受骗的合约超过21份,累计骗取金额超过 25 ETH。 前几天,小安比从 p0n1 大神那里听说了一种新型的蜜罐(...

SECBIT区块链安全实验室 1746

读心术:从零知识证明中提取「知识」——探索零知识证明系列(三)

本文已更新至Githubhttps://github.com/sec-bit/learning-zkp/blob/master/zkp-intro/3/zkp-pok.md 导言:有些理论非常有趣,零知识证明便是其中之一,摸索了许久,想写点什么,与大家一起讨论。本文是『探索零知识证明』系列的第三篇。全文约 7,000 字,少量数学公式。 And what, Socrates, is the fo...

SECBIT区块链安全实验室 1606

警惕!Solidity缺陷易使合约状态失控

作者:安比(SECBIT)实验室 & 轻信科技(LedgerGo) 本文以蜜罐合约和 BancorLender 合约为例,详细介绍 Solidity 语言中「未初始化的 storage 指针」问题,并追踪 Solidity 编译器关于此问题的开发进展。 安比(SECBIT)实验室在 BancorLender (0x2d820ea3A6b9302c500feeb7F6361bA1...

SECBIT区块链安全实验室 1280

ERC223及ERC827实现代码欠缺安全考虑 —— ATN Token中的CUSTOM_CALL漏洞深入分析

本文部分内容基于安比(SECBIT)实验室团队与吴玉会(轻信科技)的讨论 本文结论: ERC223, ERC827的部分实现代码引入了任意函数调用缺陷,可能会对使用这部分代码的合约带来安全漏洞。如果需要实现上述规范接口,请仔细检查实现代码。这种合约本身允许用户自定义call() 任意地址上任意函数的设计,十分危险。攻击者可以很容易地借用当前合约的身份来进行任何操作,比如盗取Token或者绕...

SECBIT区块链安全实验室 1165

从「模拟」理解零知识证明:平行宇宙与时光倒流—— 探索零知识证明系列(二)

本文作者:郭宇 本文已更新至Github https://github.com/sec-bit/learning-zkp/blob/master/zkp-intro/2/zkp-simu.md I know that I know nothing —— 苏格拉底 相信很多人都听说过零知识证明,但是只有极少数人听说过模拟,然而模拟是理解零知识的关键。 我们在第一篇文章『初识「零知识」与「证明」...

SECBIT区块链安全实验室 1154

SECBIT郭宇:智能合约审计的趋势是自动化和复杂化

8月31日晚,SECBIT安比实验师创始人郭宇及其团队做客链得得《无眠吐槽大会》,与群友们探讨合约安全问题和“漏洞”中的机会,并就智能合约安全现状、应用、关键技术、解决方案、智能合约游戏漏洞以及区块链安全的商业模式等进行了全方位的分享。 郭宇精彩观点汇总: 1、 以太坊上大量的合约存在各种花样的整数溢出漏洞,有些可以直接导致 token 归零; 2、 目前智能合约中存在最普...

SECBIT区块链安全实验室 1142

YOLO26算法保龄球馆保龄球目标检测+训练好的模型+743张数据集+pyqt可视化界面.zip

数据集可视化效果可参见下方展示。 【数据集概况】 · 检测类别(中文):[保龄球(bowling)] · 训练集:594 张 · 验证集:75 张 · 测试集:74 张 · 总计:743 张 该数据集聚焦于室内保龄球馆场景,系统性采集了多角度、多姿态下保龄球在不同运动阶段的视觉特征,为保龄球运动过程中的球体识别与轨迹分析提供了高质量标注样本,具有明确的体育训练与智能辅助系统开发价值。... 【训练曲线与评估图】 【模型训练配置】 参数 | 值 模型 | yolo26n 训练轮数 | 100 epochs 输入尺寸 | 640x640 批次大小 | 24 优化器 | auto 初始学习率 | 0.01 训练设备 【关键指标汇总】 训练了 100 个 epoch,最终轮指标: 指标 | 数值 mAP50 | **0.9938** mAP50-95 | 0.6966 Precision | 0.9740 Recall | 0.9974 train/box_loss | 0.9113 train/cls_loss | 0.2862 val/box_loss | 1.1516 val/cls_loss | 0.3116 【训练过程分析】 100 轮训练后 mAP50 达到 0.9938,模型收敛良好。Loss 曲线前段快速下降,后段趋于平稳,val_loss 无反弹,没有明显过拟合。但 mAP50-95 为 0.6966,和 mAP50 差距 0.30,定位精度仍有优化空间。 【模型性能评估】 Precision 0.9740、Recall 0.9974,精召双高,模型对保龄球的检测能力强。 【预测效果展示】 验证集预测效果较好,检测框基本准确覆盖保龄球,置信度整体偏高。 【改进建议】 1. 丰富场景多样性:补充不同光照、背景和遮挡条件下的样本。 2. 提升输入分辨率:640 ...

上一篇: PoD-Tiny——实现零信任交易的最简协议
下一篇: 初识「零知识」与「证明」
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值