搜索
NFT元宇宙Web3
近期热门

在合约中创建、证明和验证 zkSNARKs 的实用初学者指南

Founder

亲爱的朋友们,大家好,我是公众号老雅痞的小编波动,雅痞哥为了敦促我学习区块链/DAO/NFT知识,我们将单独开始一个专栏,从零开始学习。每天在公众号FastDaily和老雅痞各更新一篇。

让我们每天学点新东西,争取不白活。

欢迎大家和我一起学习进步(微信yaoyaobigc)~揪咪~

约瑟夫·斯托克曼斯 2018 年 1 月 6 日

在合约中创建、证明和验证 zkSNARKs 的实用初学者指南

动机

和许多人一样,当我第一次听说拜占庭更新时,我对 zkSNARKS 将为我们提供的所有新隐私功能感到非常兴奋——因为我根本不了解 zkSNARKs。

所以我最近花了一些时间来探索这个主题,我发现没有一个人真正讨论过如何使用 zkSNARKs 启动和运行。事实上,许多关于“zksnarks 合同”要点的评论者似乎都不知道从哪里开始。

所以我希望本教程对你有所帮助!

ZoKrates 简介

我记得我听说过一个名为ZoKrates的项目,它与以太坊和 zkSNARKs 有关。它可以让你在 Solidity 合约中创建和验证零知识证明,而无需了解“底层”实际发生的事情。ZoKrates 声称是“以太坊上的 zkSNARKs 的工具箱”。 ZoKrates 有一个内置的高级语言,可以将简单的类似 python 的脚本编译成算术电路!非常感谢ZoKrates 贡献者构建这个并帮助我完成我的 zkSNARKs 之旅!

入门

开始使用 zkSNARKs 和 ZoKrates 的最简单方法是使用 Docker。

确保你已安装并运行 docker。

在合约中创建、证明和验证 zkSNARKs 的实用初学者指南

现在我们在一个 Docker 容器中,其中包含所有可用的 ZoKrates 命令。在我们运行任何东西之前,我将为在他们的 github README 中找到的每个 ZoKrates 命令提供一些描述,因为目前没有对它们的解释。

  • compile获取用 ZoKrates 高级语言编写的文件并将其编译为算术电路(根据CConsensys 文章创建算术电路)。强制性论据-i path/to/file.code
  • setup从算术电路和“有毒废物”参数生成证明密钥和验证密钥lambda(运行 Consensys 文章中的生成器函数(pk, vk) = G(λ, C))。
  • compute-witness创建用于生成证明的“见证”。证明取决于公共和私人论点的特定值。这些值称为见证。强制性论据-a <arg1> <arg2> … <argn>
  • generate-proof创建一个依赖于见证人和证明密钥的证明(运行π = P(pk, x, w)Consensys 文章中的证明功能)。
  • export-verifier – 创建一个verifier.sol包含硬编码验证者密钥和公共函数的 Solidity 合约文件verifyTx。这个公共函数接受一个证明和一个公共输入。当verifyTx被调用时,它会运行V(vk, x, π)Consensys 文章中的一个版本的验证器函数,又名神秘zksnarkverify函数!

现在我们有了 ZoKrates 命令行可以做什么的参考,让我们在以太坊区块链上构建、证明和验证 zkSNARK!

谁运行哪些功能以及何时运行?

为了解释所有这些 ZoKrates 函数是如何组合在一起的,我们假设三个实体:(1)Charlie,一个可信赖的第三者,生成并销毁“有毒废物”参数lambda,(2)Alice,一个有兴趣向以太坊证明某些东西的用户社区没有透露她所有的秘密,以及 (3) Bob,一个观察以太坊区块链上交易的观察者。

Charlie(受信任的第三方)

首先,Charlie想出了一个他认为对人们有用的“程序”(算术电路)。他创建了一个有用的程序,接受公共和私人输入。他运行生成器函数G,销毁并与以太坊社区lambda 共享证明密钥pk和验证密钥。vk最后,他创建了一个 Solidity 合约,其中包含vk硬编码的验证密钥。该合约还具有一个公共功能,用户可以向其提交证明和输入,称为verifyTx.

Alice(合约用户)

接下来是Alice。她认为 Charlie 的程序非常有用,并希望用它来向以太坊社区证明一些东西,但是不会透露所有有助于她证明的价值。她运行证明功能P,输入她的见证人和公开可用的证明密钥pk。她将生成的证明连同她的公开输入一起发送到 Charlie 的函数verifyTx。由于 Alice 所做的一切都是正确的,因此验证了证明和verifyTx输出true。

Bob(观察者)

与此同时,Bob一直在看Charlie的合同。他看到 Alice 已向该verifyTx函数发送了一笔交易,并且该函数返回了true。true他可以肯定,只有当 Alice 提供了由 Charlie 的证明密钥生成的证明pk并且 Alice 的公共和私人输入满足 Charlie 程序的必要约束时,该函数才会输出。换句话说,他可以确定 Alice 的证明是有效的,同时仍然对她在证明中的私人输入一无所知。

使用 zkSNARKs 进行测试

一个具体的例子

Charlie(受信任的第三方)

首先让我们看一下 ZoKrates 命令受信任方 Charlie 运行的是哪个 ZoKrates。Charlie 认为,拥有一个用户可以证明他们知道一组三个数字的总和为 的合同对以太坊社区是有益的15。他认为这种类型的证明将受益于一些隐私,因此他设计了一个程序,该程序接受一个公共输入和两个私人输入,并断言三者之和等于15。

Charlie 的程序看起来像这样,假设我们在 ZoKrates 根目录中,他将它保存到一个名为 sumsToFifteen.code.

在合约中创建、证明和验证 zkSNARKs 的实用初学者指南

在 Charlie 的程序中,x是公共输入,s1并且s2是秘密值(ZoKrates 当前已指定,因此秘密值不会显式传递给函数。请记住,ZoKrates 是一个新项目,并且是一个 WIP,因此可能会涉及很多细节将来改变)。程序的第二行是断言语句。如果传递给它的值导致断言失败,用户将无法为此程序生成证明。在第三行,我们看到如果从这个程序构造的证明得到验证,它将输出1.

Charlie 将这个用 ZoKrates 高级语言编写的程序编译成带有compile命令的算术电路。

在合约中创建、证明和验证 zkSNARKs 的实用初学者指南

这会输出一个机器可读的电路文件out和一个人类可读的电路文件out.code。Charlie 然后运行生成器函数G,给我们一个证明者密钥pk和验证密钥vk。

在合约中创建、证明和验证 zkSNARKs 的实用初学者指南

此命令创建一个verifier.solSolidity 合约文件,其中包含我们的验证密钥和一个名为verifyTx. Charlie 将此合约部署到以太坊网络。

Alice(合约用户)

完成 Charlie 的辛勤工作后,让我们看看 ZoKrates 命令合约用户 Alice 运行了哪些命令。Alice碰巧知道三个相加的数字,15,但由于数字隐私对她来说是一个大问题,她特别被查理的程序所吸引。爱丽丝相应地选择她的公共和私人输入:

在合约中创建、证明和验证 zkSNARKs 的实用初学者指南

她首先计算她的证人:

在合约中创建、证明和验证 zkSNARKs 的实用初学者指南

(当前指定了 ZoKrates,以便在-a标志之后传递公共参数,但之后以交互方式传递私有参数。同样,ZoKrates 是一个 WIP,将来可能会更改)。3Alice然后在得到提示后将她的私人值传递给 ZoKrates 7。然后,Zokrates 创建一个名为的文件,witness其中包含构成见证的公共和私有值。Alice 从 Charlie 那里获取公开可用的proving.key文件并生成她的证明。

在合约中创建、证明和验证 zkSNARKs 的实用初学者指南

ZoKrates 不会为证明创建文件,而是将值打印到控制台。它应该看起来像这样:

A = 0x1628f3170cc16d40aad2e8fa1ab084f542fcb12e75ce1add62891dd75ba1ffd7, 0x11b20d11a0da724e41f7e2dc4d217b3f068b4e767f521a9ea371e77e496cc54

A_p = 0x1a4406c4ab38715a6f7624ece480aa0e8ca0413514d70506856af0595a853bc3, 0x2553e174040723a6bf5ea2188d2a1429bb01b13084c4af5b51701e6077716980

B = [0x27c9878700f09edc60cf23d3fb486fe50726f136ff46ad48653a3e7254ae3020, 0xe35b33188dc2f47618248e4f12a97026c3acdef9b4d021bf94e7b6d9e8ffbb6], [0x64cf25d53d57e2931d58d22fe34122fa12def64579c02d0227a496f31678cf8, 0x26212d004463c9ff80fc65f1f32321333b90de63b6b35805ef24be8b692afb28]

B_p = 0x175e0abe73317b738fd5e9fd1d2e3cb48124be9f7ae8080b8dbe419b224e96a6, 0x85444b7ef6feafa8754bdd3ca0be17d245f13e8cc89c37e7451b55555f6ce9d

C = 0x297a60f02d72bacf12a58bae75d4f330bed184854c3171adc6a65bb708466a76, 0x16b72260e7854535b0a821dd41683a28c89b0d9fcd77d36a157ba709996b490

C_p = 0x29ea33c3da75cd937e86aaf6503ec67d18bde775440da90a492966b2eb9081fe, 0x13fcc4b019b05bc82cd95a6c8dc880d4da92c53abd2ed449bd393e5561d21583

H = 0x2693e070bade67fb06a55fe834313f97e3562aa42c46d33c73fccb8f9fd9c2de, 0x26415689c4f4681680201c1975239c8f454ac4b2217486bc26d92e9dcacb58d7

K = 0x11afe3c25ff3821b8b42fde5a85b734cf6000c4b77ec57e08ff5d4386c60c72a, 0x24174487b1d642e4db86689542b8d6d9e97ec56fcd654051e96e36a8b74ea9ef

这些是构成 zkSNARKs 证明的八个变量。Charlie 的合约的verifyTx功能是通过接受上面代表证明的八个值以及一组公共输入来工作。程序的预期输出也被认为是公共输入,因此 Alice 组装她的公共输入数组如下:

在合约中创建、证明和验证 zkSNARKs 的实用初学者指南

然后,在她首选的 web3 实现中,她将状态更改事务发送到此函数。由于 Alice 做的一切都正确,verifyTx函数返回true. 重要的是要注意 Alice 的证明与她的证人是硬连线的。如果她想证明另一组值总和,15她将需要计算一个新的见证人和来自该见证人的新证明。这个新证明也将适用于查理现有的已部署合约。

注意: 我发现使用 .call() 访问此函数会在程序到达我假设正在调用预编译的拜占庭合约的一些汇编代码时引发错误。我不知道为什么需要进行交易而不是调用,但这就是它的方式。将此交易设置为较高的Gas限制也很重要,因为验证会使用大量Gas。如果交易正在恢复,请尝试设置一个高Gas限制并从那里开始工作。

Bob(观察者)

鲍勃一直在密切关注查理的合同。作为怀疑论者,他不希望任何人错误地声称他们知道三个数字相加而15没有证据。但 Bob 也尊重证明者的隐私权,如果向他提供有效的零知识证明,他不需要知道所有三个数字。他观察Alice的交易,并且由于verifyTx函数返回true,他可以保持对Alice的秘密输入一无所知,同时确信Alice确实知道一组三个数字的总和为15。

这就是我们可以使用 ZoKrates 在以太坊区块链上构建、证明和验证零知识证明的方式!我希望你喜欢本教程,并发现自己实现 zkSNARKs 很有用!

最后的一些想法

zkSNARKS 有哪些应用?

zkSNARKs 为 Alice 等证明者提供了一层隐私保护。她可以对其他人隐藏的值执行操作。但是,如果她希望Bob等外部观察者与她隐藏的价值观互动呢?事实证明,事情并没有那么简单。

例如,当我开始探索 zkSNARKs 时,我认为在不使用随机预言或提交-显示类型方案的区块链上构建“正面或反面”类型的猜谜游戏会很酷。Alice 可以向存储在合约中的证明提交一个秘密值(或1或0),然后 Bob 可以调用一个函数,将 Alice 的存储证明和他对verifyTx函数的公共参数的猜测提交。就像是:

在合约中创建、证明和验证 zkSNARKs 的实用初学者指南

这可行,但问题是 Alice 已经公开了她的证明。Bob 可以在向网络提交任何内容之前测试所有两种可能性(0或1)链下(因为他可以使用证明和验证密钥),从而保证他对主网所做的每个猜测都是正确的,因此总是获胜。这可以扩展到一个有更多选择的猜谜游戏,但问题仍然是它很容易被暴力破解。

或者,Alice可以将答案的散列存储到区块链,并且像Bob这样的观察者可以将他知道秘密值的证明连同Alice存储的散列一起提交给verifyTX函数。证明可以采取以下形式:

在合约中创建、证明和验证 zkSNARKs 的实用初学者指南

不幸的是,在这个例子中,Bob 也很容易与系统博弈,因为它们只有两个值,0并且1。他可以轻松地在链下计算他们的哈希值,并在交易前查看它们是否与存储在合约中的价值相匹配。Alice 可以给她的哈希加盐(一种算法),但这也不会让游戏变得有趣,因为现在 Bob 的问题已经变成了暴力破解的反向哈希。

似乎涉及 zkSNARK 的应用程序允许证明者自己维护一个秘密并对这个秘密执行操作,但不允许其他任何人以有意义的方式与这个秘密进行交互。对于外部观察者来说,这些秘密要么无法弄清楚并因此与之交互(例如,反转加盐哈希),要么非常容易暴力破解链下。

在 Consensys 文章的机密交易示例中,看起来两个人正在就隐藏的值进行交互,但实际上,该示例更类似于一个人在她自己拥有的两个钱包地址之间发送代币。这是因为两个人都需要知道w.value交易的秘密。不是证明者 Alice 和观察者 Bob 创建交易。是 Alice1 和 Alice2 创建了一个机密交易。

不幸的是,虽然这使得正面或反面这样的酷游戏无法实现,但我们可以看到 zkSNARKs 是维护个人隐私的强大工具。在两个人事先共享一个秘密值的情况下,它们也能很好地工作。

希望本教程对你有所帮助!把我的理解写下来,让我觉得我理解了如何在实践中使用 zkSNARKs,这对我有很大帮助。

附录

示例 Solidity 合约 (Charlie)

SumsToFifteen.sol

(定制合同)

在合约中创建、证明和验证 zkSNARKs 的实用初学者指南

验证者.sol

(ZoKratesexport-verifier命令的输出)

pragma solidity ^0.4.14;

library Pairing {

struct G1Point {

uint X;

uint Y;

}

// Encoding of field elements is: X[0] * z + X[1]

struct G2Point {

uint[2] X;

uint[2] Y;

}

/// @return the generator of G1

function P1() internal returns (G1Point) {

return G1Point(1, 2);

}

/// @return the generator of G2

function P2() internal returns (G2Point) {

return G2Point(

[11559732032986387107991004021392285783925812861821192530917403151452391805634,

10857046999023057135944570762232829481370756359578518086990519993285655852781],

[4082367875863433681332203403145435568316851327593401208105741076214120093531,

8495653923123431417604973247489272438418190587263600148770280649306958101930]

);

}

/// @return the negation of p, i.e. p.add(p.negate()) should be zero.

function negate(G1Point p) internal returns (G1Point) {

// The prime q in the base field F_q for G1

uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;

if (p.X == 0 && p.Y == 0)

return G1Point(0, 0);

return G1Point(p.X, q – (p.Y % q));

}

/// @return the sum of two points of G1

function add(G1Point p1, G1Point p2) internal returns (G1Point r) {

uint[4] memory input;

input[0] = p1.X;

input[1] = p1.Y;

input[2] = p2.X;

input[3] = p2.Y;

bool success;

assembly {

success := call(sub(gas, 2000), 6, 0, input, 0xc0, r, 0x60)

// Use “invalid” to make gas estimation work

switch success case 0 { invalid }

}

require(success);

}

/// @return the product of a point on G1 and a scalar, i.e.

/// p == p.mul(1) and p.add(p) == p.mul(2) for all points p.

function mul(G1Point p, 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);

}

/// @return the result of computing the pairing check

/// e(p1[0], p2[0]) * …. * e(p1[n], p2[n]) == 1

/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should

/// return true.

function pairing(G1Point[] p1, G2Point[] p2) internal returns (bool) {

require(p1.length == p2.length);

uint elements = p1.length;

uint inputSize = elements * 6;

uint[] memory input = new uint[](inputSize);

for (uint i = 0; i < elements; i++)

{

input[i * 6 + 0] = p1[i].X;

input[i * 6 + 1] = p1[i].Y;

input[i * 6 + 2] = p2[i].X[0];

input[i * 6 + 3] = p2[i].X[1];

input[i * 6 + 4] = p2[i].Y[0];

input[i * 6 + 5] = p2[i].Y[1];

}

uint[1] memory out;

bool success;

assembly {

success := call(sub(gas, 2000), 8, 0, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)

// Use “invalid” to make gas estimation work

switch success case 0 { invalid }

}

require(success);

return out[0] != 0;

}

/// Convenience method for a pairing check for two pairs.

function pairingProd2(G1Point a1, G2Point a2, G1Point b1, G2Point b2) internal returns (bool) {

G1Point[] memory p1 = new G1Point[](2);

G2Point[] memory p2 = new G2Point[](2);

p1[0] = a1;

p1[1] = b1;

p2[0] = a2;

p2[1] = b2;

return pairing(p1, p2);

}

/// Convenience method for a pairing check for three pairs.

function pairingProd3(

G1Point a1, G2Point a2,

G1Point b1, G2Point b2,

G1Point c1, G2Point c2

) internal returns (bool) {

G1Point[] memory p1 = new G1Point[](3);

G2Point[] memory p2 = new G2Point[](3);

p1[0] = a1;

p1[1] = b1;

p1[2] = c1;

p2[0] = a2;

p2[1] = b2;

p2[2] = c2;

return pairing(p1, p2);

}

/// Convenience method for a pairing check for four pairs.

function pairingProd4(

G1Point a1, G2Point a2,

G1Point b1, G2Point b2,

G1Point c1, G2Point c2,

G1Point d1, G2Point d2

) internal returns (bool) {

G1Point[] memory p1 = new G1Point[](4);

G2Point[] memory p2 = new G2Point[](4);

p1[0] = a1;

p1[1] = b1;

p1[2] = c1;

p1[3] = d1;

p2[0] = a2;

p2[1] = b2;

p2[2] = c2;

p2[3] = d2;

return pairing(p1, p2);

}

}

contract Verifier {

using Pairing for *;

struct VerifyingKey {

Pairing.G2Point A;

Pairing.G1Point B;

Pairing.G2Point C;

Pairing.G2Point gamma;

Pairing.G1Point gammaBeta1;

Pairing.G2Point gammaBeta2;

Pairing.G2Point Z;

Pairing.G1Point[] IC;

}

struct Proof {

Pairing.G1Point A;

Pairing.G1Point A_p;

Pairing.G2Point B;

Pairing.G1Point B_p;

Pairing.G1Point C;

Pairing.G1Point C_p;

Pairing.G1Point K;

Pairing.G1Point H;

}

function verifyingKey() internal returns (VerifyingKey vk) {

vk.A = Pairing.G2Point([0x11cdfdd85c8506e01b1013980776315a6d861d5505fe3b2d70ca66646f08adea, 0x1d831f34d31e8094f09b7fd8249f545073ef3f8d1038bf71248529a143fdebf3], [0x17ec9e42908c8624c32dcdb7b76c64acf53b6d4ee72444d3a7c1fe8e00f5d7fa, 0x2fbea9b20d6443c407819f819e0ade7a07c030e9f62894dbf92dad1a55a1614d]);

vk.B = Pairing.G1Point(0x10cf27740851709989f00203df5525ecc3577bf044eadef05037453b95c35f40, 0x224686b18747c89d9bef1039e945efb497ee7ff669011c14c6ca3a7778578324);

vk.C = Pairing.G2Point([0xd02131a4f3d1f61e40b25666540d93b7db79f76fa35f0f9d7a75ac2a4e23856, 0x4fb6e315e432313cdb9fbce5660354dd6fb56432b7efa72f8bf9c38cd750ef1], [0x1ae71edad4c83cda00b5a545e3f530f15fff83863d2db70b47f1a640c3c4f154, 0x224004ca2456ac33a7f1c9594b9b30f31370f432907ac4b5e72664b74254b9a7]);

vk.gamma = Pairing.G2Point([0x16375cb516444080a3d506e3ccda9f36a9b533d32732600125fe23b95d424719, 0x14b036bf21e18810e6b3549f868b9897c1bc0a5a50b17a3b2a0db67215795254], [0x261fbb7c90d8f47bb64b866d8be09b66d5b074f1ca7329310473dc7eaf167eb3, 0x2c05775885afcb722cd4d7c832a6d00b08d108697b044d2ac05ab595dfcf6f1a]);

vk.gammaBeta1 = Pairing.G1Point(0x1b86641088fe2985bd3c4b1195e7792ae61314561a20bd28622a3b10716d5b79, 0x272f35e571a9c28f54c969a0e093f3e2d92962857f67bdf6122e98b14389153);

vk.gammaBeta2 = Pairing.G2Point([0x961ab4f5fd50c437b4aace5efda67eb910235662a3e1d4f4c07073361ad8c14, 0x16585be5bc76e6fb26750d0361efc293ff7ce6fe63d40efa936dcda52e89d88a], [0x12d8cc318710026ebdd483d4a8e26951e7728682195488aa8231d33ce55a7211, 0x1babe275048dbabbda7200de77538ba582abc0857030ddeef52ea64c31406d8a]);

vk.Z = Pairing.G2Point([0x1532128acd3ae189f8cac212620f6e93a47da24350534a5383804e18b7ec4497, 0x2014cf88774f460a6f003dd1a4d6e40db890de1ca4694219ea1245041f73be03], [0xd368d63297b3ee0e42219e1b938555a3d7d2249937bc683f195043803590583, 0x1278c675d5eecfde121e1d95ac0b1f8c8a6fa920f176f016893acebecdf478e5]);

vk.IC = new Pairing.G1Point[](3);

vk.IC[0] = Pairing.G1Point(0x10682c32b1cbdd9d48d08ba6397853ae73ee82dfc2441dd345922460cc78d508, 0x2fc117c0cdb41a93bdf87416122359c6d065f689c02f08d9d86924e8d0328d77);

vk.IC[1] = Pairing.G1Point(0x2188a0de08297f728150224fe8a0796a17d7499d5f774b9b765b324cfbbb2ea9, 0x2ceb95f152b45bd36d8662e0d211d1b3fc912fe6935ec400d7e2fb5d7c27e3da);

vk.IC[2] = Pairing.G1Point(0x13c07e1ab1bd0dc50a121c54b1774d758c9eebb83673f728678a92528253832c, 0xe38e2d5cfc5c4e6b4f63e5e4e1496b86fd8b627c78af3e130cda3ad5c6f328d);

}

function verify(uint[] input, Proof proof) internal returns (uint) {

VerifyingKey memory vk = verifyingKey();

require(input.length + 1 == vk.IC.length);

// Compute the linear combination vk_x

Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0);

for (uint i = 0; i < input.length; i++)

vk_x = Pairing.add(vk_x, Pairing.mul(vk.IC[i + 1], input[i]));

vk_x = Pairing.add(vk_x, vk.IC[0]);

if (!Pairing.pairingProd2(proof.A, vk.A, Pairing.negate(proof.A_p), Pairing.P2())) return 1;

if (!Pairing.pairingProd2(vk.B, proof.B, Pairing.negate(proof.B_p), Pairing.P2())) return 2;

if (!Pairing.pairingProd2(proof.C, vk.C, Pairing.negate(proof.C_p), Pairing.P2())) return 3;

if (!Pairing.pairingProd3(

proof.K, vk.gamma,

Pairing.negate(Pairing.add(vk_x, Pairing.add(proof.A, proof.C))), vk.gammaBeta2,

Pairing.negate(vk.gammaBeta1), proof.B

)) return 4;

if (!Pairing.pairingProd3(

Pairing.add(vk_x, proof.A), proof.B,

Pairing.negate(proof.H), vk.Z,

Pairing.negate(proof.C), Pairing.P2()

)) return 5;

return 0;

}

event Verified(string);

function verifyTx(

uint[2] a,

uint[2] a_p,

uint[2][2] b,

uint[2] b_p,

uint[2] c,

uint[2] c_p,

uint[2] h,

uint[2] k,

uint[2] input

) returns (bool r) {

Proof memory proof;

proof.A = Pairing.G1Point(a[0], a[1]);

proof.A_p = Pairing.G1Point(a_p[0], a_p[1]);

proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);

proof.B_p = Pairing.G1Point(b_p[0], b_p[1]);

proof.C = Pairing.G1Point(c[0], c[1]);

proof.C_p = Pairing.G1Point(c_p[0], c_p[1]);

proof.H = Pairing.G1Point(h[0], h[1]);

proof.K = Pairing.G1Point(k[0], k[1]);

uint[] memory inputValues = new uint[](input.length);

for(uint i = 0; i < input.length; i++){

inputValues[i] = input[i];

}

if (verify(inputValues, proof) == 0) {

Verified(“Transaction successfully verified.”);

return true;

} else {

return false;

}

}

}

Python 中的示例 Web3 (Alice)

from web3.contract import ConciseContract

from web3 import Web3, HTTPProvider

import json

web3 = Web3(HTTPProvider(‘http://localhost:8545’))

# Get the address and ABI of the contract

address = ‘0xB4D425cF6fFa2ACD4d8e08A5427F846FCF20899f’

abi = json.loads(‘[{“constant”: true, “inputs”: [], “name”: “success”, “outputs”: [{“name”: “”, “type”: “bool”}], “payable”: false, “stateMutability”: “view”, “type”: “function”}, {“constant”: false, “inputs”: [{“name”: “a”, “type”: “uint256[2]”}, {“name”: “a_p”, “type”: “uint256[2]”}, {“name”: “b”, “type”: “uint256[2][2]”}, {“name”: “b_p”, “type”: “uint256[2]”}, {“name”: “c”, “type”: “uint256[2]”}, {“name”: “c_p”, “type”: “uint256[2]”}, {“name”: “h”, “type”: “uint256[2]”}, {“name”: “k”, “type”: “uint256[2]”}, {“name”: “input”, “type”: “uint256[2]”}], “name”: “verifyFifteen”, “outputs”: [], “payable”: false, “stateMutability”: “nonpayable”, “type”: “function”}, {“constant”: true, “inputs”: [], “name”: “flag”, “outputs”: [{“name”: “”, “type”: “uint256”}], “payable”: false, “stateMutability”: “view”, “type”: “function”}, {“constant”: false, “inputs”: [{“name”: “a”, “type”: “uint256[2]”}, {“name”: “a_p”, “type”: “uint256[2]”}, {“name”: “b”, “type”: “uint256[2][2]”}, {“name”: “b_p”, “type”: “uint256[2]”}, {“name”: “c”, “type”: “uint256[2]”}, {“name”: “c_p”, “type”: “uint256[2]”}, {“name”: “h”, “type”: “uint256[2]”}, {“name”: “k”, “type”: “uint256[2]”}, {“name”: “input”, “type”: “uint256[2]”}], “name”: “verifyTx”, “outputs”: [{“name”: “r”, “type”: “bool”}], “payable”: false, “stateMutability”: “nonpayable”, “type”: “function”}, {“anonymous”: false, “inputs”: [{“indexed”: false, “name”: “”, “type”: “string”}], “name”: “Verified”, “type”: “event”}]’)

# Create a contract object

contract = web3.eth.contract(

address,

abi=abi,

ContractFactoryClass=ConciseContract,

)

# Proof generated from Zokrates

A = [0x1628f3170cc16d40aad2e8fa1ab084f542fcb12e75ce1add62891dd75ba1ffd7, 0x11b20d11a0da724e41f7e2dc4d217b3f068b4e767f521a9ea371e77e496cc54]

A_p = [0x1a4406c4ab38715a6f7624ece480aa0e8ca0413514d70506856af0595a853bc3, 0x2553e174040723a6bf5ea2188d2a1429bb01b13084c4af5b51701e6077716980]

B = [[0x27c9878700f09edc60cf23d3fb486fe50726f136ff46ad48653a3e7254ae3020, 0xe35b33188dc2f47618248e4f12a97026c3acdef9b4d021bf94e7b6d9e8ffbb6], [0x64cf25d53d57e2931d58d22fe34122fa12def64579c02d0227a496f31678cf8, 0x26212d004463c9ff80fc65f1f32321333b90de63b6b35805ef24be8b692afb28]]

B_p = [0x175e0abe73317b738fd5e9fd1d2e3cb48124be9f7ae8080b8dbe419b224e96a6, 0x85444b7ef6feafa8754bdd3ca0be17d245f13e8cc89c37e7451b55555f6ce9d]

C = [0x297a60f02d72bacf12a58bae75d4f330bed184854c3171adc6a65bb708466a76, 0x16b72260e7854535b0a821dd41683a28c89b0d9fcd77d36a157ba709996b490]

C_p = [0x29ea33c3da75cd937e86aaf6503ec67d18bde775440da90a492966b2eb9081fe, 0x13fcc4b019b05bc82cd95a6c8dc880d4da92c53abd2ed449bd393e5561d21583]

H = [0x2693e070bade67fb06a55fe834313f97e3562aa42c46d33c73fccb8f9fd9c2de, 0x26415689c4f4681680201c1975239c8f454ac4b2217486bc26d92e9dcacb58d7]

K = [0x11afe3c25ff3821b8b42fde5a85b734cf6000c4b77ec57e08ff5d4386c60c72a, 0x24174487b1d642e4db86689542b8d6d9e97ec56fcd654051e96e36a8b74ea9ef]

# Set gas and gas price

params = {

‘gasPrice’:20000000000,

‘gas’: 4000000,

‘from’:web3.eth.accounts[0],

}

# Correct input

I = [5, 1]

# Verify

txhash = contract.verifyFifteen(A, A_p, B, B_p, C, C_p, H, K, I, transact=params)

# Check success

success = contract.success()

print(success)

>> True

# Incorrect input

I = [6, 1]

# Verify

txhash = contract.verifyFifteen(A, A_p, B, B_p, C, C_p, H, K, I, transact=params)

# Check success

success = contract.success()

print(success)

>> False

编辑于 2022-05-10 23:23
「 真诚赞赏,手留余香 」
赞赏

发表评论已发布0

手机APP 意见反馈 返回顶部 返回底部