博客
关于我
Circom and Snarkjs,基于以太坊的零知识证明实现
阅读量:285 次
发布时间:2019-03-01

本文共 13988 字,大约阅读时间需要 46 分钟。

Circom is a DSL language to create generic statments (circuits) to be used in zero knowledge proofs. Snarkjs is an alternative implementation of zkSnarks Pinoccio and Groth16 protocols. It allows to generate proofs and verify them offchain and in the Ethereum chain.

中有大量例子。

在这里插入图片描述

是对zkSnarks(BN128曲线)的Pinoccio和Groth16协议的实现(–protocol groth)。

在这里插入图片描述

可参照进行体验。基本的流程遵循:

在这里插入图片描述

Snarkjs可借鉴学习的地方:

1)支持offchain和onchain验证;
2)其中的calculatewitnessprintconstraints很直观,值得学习;
3)generateverifier生成的verifier.sol智能合约,是基于《Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture》论文Page-25页的算法实现。

//// Copyright 2017 Christian Reitwiessner// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.pragma solidity ^0.4.17;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() pure internal returns (G1Point) {        return G1Point(1, 2);    }    /// @return the generator of G2    function P2() pure internal returns (G2Point) {        // Original code point        return G2Point(            [11559732032986387107991004021392285783925812861821192530917403151452391805634,             10857046999023057135944570762232829481370756359578518086990519993285655852781],            [4082367875863433681332203403145435568316851327593401208105741076214120093531,             8495653923123431417604973247489272438418190587263600148770280649306958101930]        );/*        // Changed by Jordi point        return G2Point(            [10857046999023057135944570762232829481370756359578518086990519993285655852781,             11559732032986387107991004021392285783925812861821192530917403151452391805634],            [8495653923123431417604973247489272438418190587263600148770280649306958101930,             4082367875863433681332203403145435568316851327593401208105741076214120093531]        );*/    }    /// @return the negation of p, i.e. p.addition(p.negate()) should be zero.    function negate(G1Point p) pure 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 addition(G1Point p1, G1Point p2) view 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 := staticcall(sub(gas, 2000), 6, 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.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.    function scalar_mul(G1Point p, uint s) view internal returns (G1Point r) {        uint[3] memory input;        input[0] = p.X;        input[1] = p.Y;        input[2] = s;        bool success;        assembly {            success := staticcall(sub(gas, 2000), 7, 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) view 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 := staticcall(sub(gas, 2000), 8, 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) view 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    ) view 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    ) view 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() pure internal returns (VerifyingKey vk) {        vk.A = Pairing.G2Point([11471555659227993821558309627390598340144479079056433628778102631560356945196,17239341673537703655415242914137247675383548768632132758504283130453992776723], [21840111305325018621811764524080084607281106943083417610062232151753686634389,13067312946253218821063730225751104957278386376461583544396248901695822639709]);        vk.B = Pairing.G1Point(2721879735262596409289531315625821875211187332406308292154995988594906268500,11608983819712298545694042439685471022716966939419357601529919546552292307000);        vk.C = Pairing.G2Point([19656925059139513569729113044871911422430902049677076718711718313620952900563,5576668198704353407832150137561073878345331579977637943174817874706151661393], [7281295213299204051302698314874315382763807448228276777317130979029692931165,7916695789970843503650338800940601383317981493254576033370139751926979927902]);        vk.gamma = Pairing.G2Point([18385334434127063906954531571970107990014968017682766911682537921858279464260,8929675488863538648285654541062334049652723184901164017871711012593339580980], [19432375795531858054188736522402749208417298354515266283889952586861218556876,13161708584257346412896507856831520204094726409907232342829227463532753486821]);        vk.gammaBeta1 = Pairing.G1Point(19309821543521419388092516467492689640912329403760280872194124727606354537632,20353285109717075092024467509541543771816731504732018361823602825239940096506);        vk.gammaBeta2 = Pairing.G2Point([3201520417051381658696464743108694422098403880081178875590449795369617089487,20359564875543220411653113034498547098466912194746756771160720992127018464105], [21510509108235571401228940597112459120626333092208380691682294738065279880961,8755324618659484077861518310650940009846072237432653448950145505233310290697]);        vk.Z = Pairing.G2Point([8835066318839081768498527350557716481288255937020646417565557742609989390821,5953981016178255894550021108862323931501144929290961519398762283427286942730], [3417806769259177697822528101809787162567605994409410699303553780002102855950,5695524357745453823070393157667727062025352362824114638963751112519736534075]);        vk.IC = new Pairing.G1Point[](2);        vk.IC[0] = Pairing.G1Point(17891620820348589195818796761006959184449993997577571636032322491763190514010,12899317037026433033044857347124399643982755957431223448882373114262398444006);        vk.IC[1] = Pairing.G1Point(21849736562685629033103191129599121428571890454117937621414449791469254767436,7965584159993075250688571980216552879225831779231603043091430714075231145743);    }    function verify(uint[] input, Proof proof) view 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.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i]));        vk_x = Pairing.addition(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.addition(vk_x, Pairing.addition(proof.A, proof.C))), vk.gammaBeta2,            Pairing.negate(vk.gammaBeta1), proof.B        )) return 4;        if (!Pairing.pairingProd3(                Pairing.addition(vk_x, proof.A), proof.B,                Pairing.negate(proof.H), vk.Z,                Pairing.negate(proof.C), Pairing.P2()        )) return 5;        return 0;    }    function verifyProof(            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[1] input        ) view public 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) {            return true;        } else {            return false;        }    }}

在这里插入图片描述

在这里插入图片描述
Snarkjs有性能瓶颈,在处理百万级的constraints,需要的内存很大,后续有计划采用Julia重写(Julia 是一个面向科学计算的高性能动态高级程序设计语言,擅长数值计算)。具体参见
在这里插入图片描述

verifier.sol中含verifier和pairing两个智能合约,使用时,注意:

1)不要使用JavaScirpt VM(网页会崩溃),可使用MetaMask+Ropsten测试网络,测试ether可通过测试水管获取。
2)部署时,仅需部署verifier智能合约即可。
3)snarkjs generatecall生成的内容贴入到verifyProof方框后即可,点击call按钮,返回值为true,说明验证通过。

["0x2dfb574f7e62a4d230dddf8d94113b72fcdab705a3db3226f6efdb794e1789d9", "0x248e14f6bce3d13e8957eefea9935eef578fa6013c6563f2d58fd59e352e0886"],["0x085fb4366ea4140449a9f36e1d113f24059a8aff80f54c324fbdb0cf64699975", "0x103b4b855dcc74f419dfd46b3b462eeb8e554fff68ccbbc745152236a91817cb"],[["0x2aebc30dafa7eefae49c21d03687823745bd332f409ee877afca6feeb0e1240e", "0x166de7fa3dad364c96d8d94635c7cb84a2859c1ddcaf16ef0bb30a76c5eb0687"],["0x2305286bb810764dcd0088352ca439ad79b1b00a05f9cc1a16467cb486471e9d", "0x18e66e9dc43142b7cf3a7bc0e2af54baf956fb757d4c03d594abed7b6e735af1"]],["0x0e7a5775de7bdf7258fce0eb7f12422cbfd02f7ce30de00061847969d9c808a4", "0x02103f55b366e862fa07b18ed1c2731c4e909b642295902bd81d360d42fccc3f"],["0x25b2c759605d59687a7171dfa895cb5e7486079b4a2ebae9267a0eb2544968da", "0x277790ef0262b98997a0fa60cc79ab2ce28a777bafb22d213d0d5706953c4c86"],["0x069fe35474bfa91b4e1edab772a7ae66dae6fc7b77e283462ccc32b54b5b2f9e", "0x06fdf5b40ad74ccbcbe0ee6aca7c702f86631ee900f9ce753a47eb21daaa329a"],["0x17d9388be73e9c093c40e789099c262881b0df6e759d0207c25ebbd2263b260f", "0x15e1b6a737c9f2001527040fbba111fd1b9606bca3fc58d3421ec1a95891d269"],["0x0a7e62670f7a8a5ee4f5d501df479cc951053f0f4209a7a1f2b7b263fd447744", "0x0e7f923878de5f6c4cdf3ad21b37e9f1dea419aea1e0edc30991f3c00b0ac2e5"],["0x0000000000000000000000000000000000000000000000000000000000000021"]

4)初次配置MetaMask时,若Remix选择Injected Web3无法切换,重启浏览器即可生效。

在这里插入图片描述

在这里插入图片描述

转载地址:http://puqx.baihongyu.com/

你可能感兴趣的文章
navicat 添加外键1215错误
查看>>
navicat 系列软件一点击菜单栏就闪退
查看>>
navicat 自动关闭_干掉Navicat!MySQL官方客户端到底行不行?
查看>>
Navicat 设置时间默认值(当前最新时间)
查看>>
navicat 连接远程mysql
查看>>
navicat:2013-Lost connection to MySQL server at ‘reading initial communication packet解决方法
查看>>
Navicate for mysql 数据库设计-数据库分析
查看>>
Navicat下载和破解以及使用
查看>>
Navicat中怎样将SQLServer的表复制到MySql中
查看>>
navicat创建连接 2002-can‘t connect to server on localhost(10061)且mysql服务已启动问题
查看>>
Navicat可视化界面导入SQL文件生成数据库表
查看>>
Navicat向sqlserver中插入数据时提示:当 IDENTITY_INSERT 设置为 OFF 时,不能向表中的标识列插入显式值
查看>>
Navicat因导入的sql文件中时间数据类型有参数而报错的原因(例:datetime(3))
查看>>
Navicat如何连接MySQL
查看>>
navicat导入.sql文件出错2006- MySQLserver has gone away
查看>>
Navicat导入海量Excel数据到数据库(简易介绍)
查看>>
Navicat工具Oracle数据库复制 or 备用、恢复功能(评论都在谈论需要教)
查看>>
Navicat工具中建立数据库索引
查看>>
navicat工具查看MySQL数据库_表占用容量_占用空间是多少MB---Linux工作笔记048
查看>>
navicat怎么导出和导入数据表
查看>>