
我们基于zkSNARK实现了匿名交易的原型,以确保Waves区块链中的机密交易。 在我们的实现中,我们在BN254曲线和DSL 外接上使用Groth16证据系统。
我们解释它是如何工作的。
zkSNARKs
zkSNARK是一种加密原语,用于确认与以下方程组(约束系统)相对应的特殊数据集(证据)的知识:
⟨ai,w⟩⟨bi,w⟩+⟨ci,w⟩=0
部分证据是私人的。 这种构造使我们能够证明例如散列逆图像的知识,而无需泄露逆图像。 它也可以用于UTXO (未使用的交易(TX)输出)模型的私有交易机制中,该模型仅发布UTXO哈希,并且在zkSNARK(所有权证明,节省金额证明)中证明了交易的有效性。
zkSNARK是一种零披露的非交互式技术,也就是说,它并不意味着为了证明知识而实施的参与者之间的交互协议。 在zkSNARK技术中,证明者构造证明并将其发送给证明者-不需要其他交互。 审查员可以验证证据数据使用的正确性和正确性,而无需诉诸其他信息。 最初,zkSNARKs是作为“机密计算”协议创建的:在计算结果时,不公开计算所涉及的数据。
使用zkSNARK技术,可以实现一种提交-公开方案:证明者计算哈希,将其提供给证明者,并做出一个特殊的证明,证明他知道哈希x的逆像。 通过将x和hash的值替换为公式,并将此公式和证明传递给检查者,检查者可以确保证明者知道x。 这是匿名交易的基础:我们知道私钥和用户在智能合约上创建的具有特定金额的特定输入(未使用的UTXO)。 在不公开此数据的情况下,用户可以通过智能合约确认这是他的输入,可以处置它并将其提供给某人使用。
现在,该技术并没有在所有地方使用,因为证明是在几分钟内生成的,这对于用户来说不是很方便。
在Vitalik Buterin的文章“二次运算:从零到英雄”和Iden3的绕线电路设计文章中 ,了解有关zkSNARK编程的更多信息。
帐户模型
对于curve25519
交易,他们通常使用基于curve25519
键和地址。 该曲线不是zkSNARK友好的,因此对于匿名交易,我们使用BabyJubJub
的扭曲曲线的Edwards子组。 另外,我们使用公共密钥作为地址,因为在发送时,您需要为收件人加密数据。
UTXO模型
在我们的模型中,UTXO由一组3个参数表示:余额,所有者的公钥和唯一秘密。 区块链仅包含哈希,没有其他加密。 所有者由一个公共密钥表示,并且,如前所述,我们不在curve25519
曲线上使用公共密钥,而是在对zkSNARK友好的BabyJubJub
曲线上使用公共密钥。 UTXO ID应该是随机生成的,因为如果用户指定两个相同的ID,则他只能在其中一个上获取(花费)UTXO。 在这种情况下,只有当前用户具有相应ID的UTXO才会被阻止,其余用户则不会被阻止。 用户使用随机数生成器选择id(在id上分配了253位,因此很难产生冲突),这符合用户的利益。
要使用UTXO,您必须发布nullifier,这是UTXO的确定性功能,定义为哈希(秘密,owner_privkey)。 该值是确定性的,并且对于每个UTXO都是唯一的;只有所有者才知道。 除所有者外,没有人可以将UTXO与相应的nullifier关联。
UTXO存储在dApp哈希图中,即以合同形式。 在区块链上,UTXO被加密。 为了拿走钱,用户必须扫描区块链并尝试解密每个UTXO。
状态dapp
dApp样式包含代表两个集合的哈希映射:
因此,dApp可以验证UTXO匿名集的存在和无效符的唯一性。 这足以处理匿名转移,并防止新资产伪造和双重支出。
DApp具有3种与基本交易类型相对应的方法:
为了转移和提取资金,我们使用自己的验证程序,以确保dApp与基于BabyJubJub曲线的特殊匿名帐户进行交互。 存款是通过常规Waves帐户处理的。
佣金
对于帐户充值,将从curve25519
帐户收取费用。 对于转账和提款,将从匿名帐户中扣除佣金。 在dApp级别,它看起来像这样:
dApp支付交易本身的费用,即用于支付佣金的本机令牌将从其余额中扣除
在进出口之间,部分佣金被烧掉以废除与智能合约中的实际资产相对应的资产。
在UTXO级别,我们在处理交易时会烧掉一定数量的佣金。
交易次数
存款是一个简单的操作,每次存款都会为UTXO添加一个新元素。

传输基于2对2翻译原语。

一些输入和输出可能为零。 作为这种结构的部分示例,可以表示任何类型的简单翻译(除原子交换外的联接,拆分和其他传输)。
结论的工作方式与其他事务一样,只是不让用户创建第二个UTXO,而是让用户从dApp中撤回其UTXO。 输入端还可以有两个UTXO,出口处有两个UTXO,其余的资金和提款都发布在区块链上。

撤回或转移时,dApp会验证在其堆栈中尚未找到相应的nullifier。
使用zkSNARK,我们可以计算出交易输入的总和等于输出的总和。 在执行交易时,我们将其花在UTXO和其他零零UTXO上,这不在Merkle树中。 要使用UTXO,您需要证明其拥有者的私钥知识。 检查私钥与组生成器相乘后是否生成公钥。 因此,在不知道私钥的情况下,不能完成交易。
匿名集
我们使用8个元素的匿名集合。 目标元素是从zkSNARK公共输入中表示的集合中秘密选择的。 此方法使您可以混淆事务图(如果可以恢复UTXO交互图,则可能使事务匿名化)。
此外,可以用Merkle树的收集器替换8个元素的简单收集器。 该方法隐藏了交易图。
为了创建有效的交易,我们证明我们从UTXO集中花费了一些UTXO。 我们将zkSNARK merkle证明和UTXO数据放入私有输入,并将根哈希放入公共入口。 因此,使用SNARK,我们证明我们知道UTXO。

双重支出保护
为了防止重复支出,我们使用了nullifiers-不直接依赖于UTXO哈希的确定性函数。 为了计算无效符,我们从私钥中获取函数,证明它对应于公钥,id和UTXO哈希。 对于每个UTXO,只有一个无效符。
对于每笔交易,用过的UTXO输出的无效符应作为zkSNARK的公共条目显示。 在zkSNARK电路内部,还必须确认它属于用过的UTXO。
如果dApp合同收到非唯一的无效值,则交易将被拒绝。 因此,可以确保每个UTXO使用一次。
在他们使用UTXO之后,无效标识符将发布在dApp文章中的无效标识符列表中。 即,在散列图中与该无效符相对的位置被设置为“ true”。 在文章中发布nullifier之前,我们检查该nullifier尚未使用,这意味着可以使用具有此ID的UTXO。